From 5c6c4cccc7702bdda47caccab32fd866b380f1dd Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 8 Dec 2015 20:18:16 +0100 Subject: [PATCH 01/45] Add support for the DiveSystem iX3M series. The protocol of the iX3M series is almost identical to the protocol of the iDive series. The main difference is that the command bytes and the size of the response packets have been changed. In order to be able to communicate with the correct set of commands, the user needs to supply the correct number now. To maintain backwards compatibility, a new variant of the open function is added. --- include/libdivecomputer/divesystem_idive.h | 6 ++ src/descriptor.c | 4 + src/device.c | 2 +- src/divesystem_idive.c | 97 ++++++++++++++-------- src/divesystem_idive_parser.c | 39 +++++++-- src/libdivecomputer.symbols | 2 + src/parser.c | 2 +- 7 files changed, 110 insertions(+), 42 deletions(-) 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; From d8398529538c0fb011e56090d7002aef2736eb9a Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 21 Dec 2015 09:34:44 +0100 Subject: [PATCH 02/45] Parse the profile to retrieve the bailout gas mixes. In CC mode, only the diluents are stored in the header. The list with the OC gas mixes, which are used for bailout, are not stored in the header. In order to retrieve the bailout mixes too, we need to parse the profile and add them to the manual gas mixes. --- src/hw_ostc_parser.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index 058610d..b760d44 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -759,10 +759,24 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call ERROR (abstract->context, "Buffer overflow detected!"); return DC_STATUS_DATAFORMAT; } + + unsigned int o2 = data[offset]; + unsigned int he = data[offset + 1]; + unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, MANUAL); + if (idx >= parser->ngasmixes) { + if (idx >= NGASMIXES) { + ERROR (abstract->context, "Maximum number of gas mixes reached."); + return DC_STATUS_NOMEMORY; + } + parser->gasmix[idx].oxygen = o2; + parser->gasmix[idx].helium = he; + parser->ngasmixes = idx + 1; + } + sample.event.type = SAMPLE_EVENT_GASCHANGE2; sample.event.time = 0; sample.event.flags = 0; - sample.event.value = data[offset] | (data[offset + 1] << 16); + sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); offset += 2; length -= 2; @@ -849,10 +863,24 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call ERROR (abstract->context, "Buffer overflow detected!"); return DC_STATUS_DATAFORMAT; } + + unsigned int o2 = data[offset]; + unsigned int he = data[offset + 1]; + unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, MANUAL); + if (idx >= parser->ngasmixes) { + if (idx >= NGASMIXES) { + ERROR (abstract->context, "Maximum number of gas mixes reached."); + return DC_STATUS_NOMEMORY; + } + parser->gasmix[idx].oxygen = o2; + parser->gasmix[idx].helium = he; + parser->ngasmixes = idx + 1; + } + sample.event.type = SAMPLE_EVENT_GASCHANGE2; sample.event.time = 0; sample.event.flags = 0; - sample.event.value = data[offset] | (data[offset + 1] << 16); + sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); offset += 2; length -= 2; From 06e0de67120635ff8e7b4e383b748c9a0e978b13 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 4 Jan 2015 08:56:10 +0100 Subject: [PATCH 03/45] Add a new sample with the active gas mix. The new gasmix sample contains the index of the active gas mix. This new sample is intended as a replacement for the existing gas change events (SAMPLE_EVENT_GASCHANGE and SAMPLE_EVENT_GASCHANGE2). To maintain backwards compatibility, the legacy events are marked as deprecated but not removed yet. --- examples/universal.c | 11 +++++----- include/libdivecomputer/parser.h | 10 ++++----- src/Makefile.am | 2 +- src/atomics_cobalt_parser.c | 4 ++++ src/cressi_edy_parser.c | 4 ++++ src/diverite_nitekq_parser.c | 4 ++++ src/divesystem_idive_parser.c | 4 ++++ src/hw_ostc_parser.c | 21 ++++++++++++++++++ src/mares_iconhd_parser.c | 4 ++++ src/oceanic_atom2_parser.c | 4 ++++ src/shearwater_predator_parser.c | 24 +++++++++++++++++++++ src/suunto_d9_parser.c | 37 +++++++++++++++++++++++++++++++- src/suunto_eonsteel_parser.c | 13 ++++++----- src/suunto_vyper_parser.c | 29 ++++++++++++++++++++++++- src/uwatec_smart_parser.c | 4 ++++ 15 files changed, 156 insertions(+), 19 deletions(-) diff --git a/examples/universal.c b/examples/universal.c index 1d61ef8..b4d9b47 100644 --- a/examples/universal.c +++ b/examples/universal.c @@ -271,12 +271,8 @@ sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata) fprintf (sampledata->fp, " %.2f\n", value.temperature); break; case DC_SAMPLE_EVENT: - if (value.event.type == SAMPLE_EVENT_GASCHANGE2) { - fprintf (sampledata->fp, " \n", - value.event.value & 0xFFFF, (value.event.value >> 16) & 0xFFFF); - } else if (value.event.type == SAMPLE_EVENT_GASCHANGE) { - fprintf (sampledata->fp, " \n", - value.event.value); + if (value.event.type == SAMPLE_EVENT_GASCHANGE || value.event.type == SAMPLE_EVENT_GASCHANGE2) { + // Ignore deprecated events. } else { fprintf (sampledata->fp, " %s\n", value.event.type, value.event.time, value.event.flags, value.event.value, events[value.event.type]); @@ -310,6 +306,9 @@ sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata) fprintf (sampledata->fp, " %s\n", value.deco.time, value.deco.depth, decostop[value.deco.type]); break; + case DC_SAMPLE_GASMIX: + fprintf (sampledata->fp, " %u\n", value.gasmix); + break; default: break; } diff --git a/include/libdivecomputer/parser.h b/include/libdivecomputer/parser.h index 774e5e3..6718741 100644 --- a/include/libdivecomputer/parser.h +++ b/include/libdivecomputer/parser.h @@ -43,7 +43,8 @@ typedef enum dc_sample_type_t { DC_SAMPLE_SETPOINT, DC_SAMPLE_PPO2, DC_SAMPLE_CNS, - DC_SAMPLE_DECO + DC_SAMPLE_DECO, + DC_SAMPLE_GASMIX } dc_sample_type_t; typedef enum dc_field_type_t { @@ -74,7 +75,7 @@ typedef enum parser_sample_event_t { SAMPLE_EVENT_BOOKMARK, SAMPLE_EVENT_SURFACE, SAMPLE_EVENT_SAFETYSTOP, - SAMPLE_EVENT_GASCHANGE, /* The event value contains the O2 percentage. */ + SAMPLE_EVENT_GASCHANGE, /* Deprecated: replaced by DC_SAMPLE_GASMIX. */ SAMPLE_EVENT_SAFETYSTOP_VOLUNTARY, SAMPLE_EVENT_SAFETYSTOP_MANDATORY, SAMPLE_EVENT_DEEPSTOP, @@ -88,9 +89,7 @@ typedef enum parser_sample_event_t { SAMPLE_EVENT_RGBM, SAMPLE_EVENT_HEADING, SAMPLE_EVENT_TISSUELEVEL, - SAMPLE_EVENT_GASCHANGE2, /* The event value contains the O2 and He - percentages, packed as two 16bit integers in - respectively the low and high part. */ + SAMPLE_EVENT_GASCHANGE2, /* Deprecated: replaced by DC_SAMPLE_GASMIX. */ } parser_sample_event_t; /* For backwards compatibility */ @@ -211,6 +210,7 @@ typedef union dc_sample_value_t { unsigned int time; double depth; } deco; + unsigned int gasmix; /* Gas mix index */ } dc_sample_value_t; typedef struct dc_parser_t dc_parser_t; diff --git a/src/Makefile.am b/src/Makefile.am index f106c09..64c3649 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,5 +1,5 @@ AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include -AM_CFLAGS = $(LIBUSB_CFLAGS) +AM_CFLAGS = $(LIBUSB_CFLAGS) -DENABLE_DEPRECATED lib_LTLIBRARIES = libdivecomputer.la diff --git a/src/atomics_cobalt_parser.c b/src/atomics_cobalt_parser.c index 83bcfc7..bf4adcb 100644 --- a/src/atomics_cobalt_parser.c +++ b/src/atomics_cobalt_parser.c @@ -306,6 +306,9 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback ERROR (abstract->context, "Invalid gas mix index."); return DC_STATUS_DATAFORMAT; } + sample.gasmix = idx; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED unsigned int o2 = data[SZ_HEADER + SZ_GASMIX * idx + 4]; unsigned int he = data[SZ_HEADER + SZ_GASMIX * idx + 5]; sample.event.type = SAMPLE_EVENT_GASCHANGE2; @@ -313,6 +316,7 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback sample.event.flags = 0; sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif gasmix_previous = gasmix; } diff --git a/src/cressi_edy_parser.c b/src/cressi_edy_parser.c index 195eb41..59898f6 100644 --- a/src/cressi_edy_parser.c +++ b/src/cressi_edy_parser.c @@ -227,11 +227,15 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c return DC_STATUS_DATAFORMAT; } if (idx != gasmix) { + sample.gasmix = idx; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED sample.event.type = SAMPLE_EVENT_GASCHANGE; sample.event.time = 0; sample.event.flags = 0; sample.event.value = bcd2dec(data[0x17 - idx]); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif gasmix = idx; } } diff --git a/src/diverite_nitekq_parser.c b/src/diverite_nitekq_parser.c index deba81b..f65ba38 100644 --- a/src/diverite_nitekq_parser.c +++ b/src/diverite_nitekq_parser.c @@ -270,11 +270,15 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac // Gas change if (gasmix != gasmix_previous) { + sample.gasmix = gasmix; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED sample.event.type = SAMPLE_EVENT_GASCHANGE2; sample.event.time = 0; sample.event.flags = 0; sample.event.value = oxygen[gasmix] | (helium[gasmix] << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif gasmix_previous = gasmix; } diff --git a/src/divesystem_idive_parser.c b/src/divesystem_idive_parser.c index c1ea98c..81d1b3d 100644 --- a/src/divesystem_idive_parser.c +++ b/src/divesystem_idive_parser.c @@ -275,11 +275,15 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba ngasmixes = i + 1; } + sample.gasmix = i; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED sample.event.type = SAMPLE_EVENT_GASCHANGE2; sample.event.time = 0; sample.event.flags = 0; sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif o2_previous = o2; he_previous = he; } diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index b760d44..5a6d02f 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -616,6 +616,9 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call // Initial gas mix. if (time == samplerate && parser->initial != 0xFF) { + sample.gasmix = parser->initial; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED unsigned int idx = parser->initial; unsigned int o2 = parser->gasmix[idx].oxygen; unsigned int he = parser->gasmix[idx].helium; @@ -624,6 +627,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call sample.event.flags = 0; sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif } // Depth (mbar). @@ -708,11 +712,16 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call parser->gasmix[idx].helium = he; parser->ngasmixes = idx + 1; } + + sample.gasmix = idx; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED sample.event.type = SAMPLE_EVENT_GASCHANGE2; sample.event.time = 0; sample.event.flags = 0; sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif offset += 2; length -= 2; } @@ -729,6 +738,9 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call return DC_STATUS_DATAFORMAT; } idx--; /* Convert to a zero based index. */ + sample.gasmix = idx; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED unsigned int o2 = parser->gasmix[idx].oxygen; unsigned int he = parser->gasmix[idx].helium; sample.event.type = SAMPLE_EVENT_GASCHANGE2; @@ -736,6 +748,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call sample.event.flags = 0; sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif offset++; length--; } @@ -773,11 +786,15 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call parser->ngasmixes = idx + 1; } + sample.gasmix = idx; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED sample.event.type = SAMPLE_EVENT_GASCHANGE2; sample.event.time = 0; sample.event.flags = 0; sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif offset += 2; length -= 2; } @@ -877,11 +894,15 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call parser->ngasmixes = idx + 1; } + sample.gasmix = idx; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED sample.event.type = SAMPLE_EVENT_GASCHANGE2; sample.event.time = 0; sample.event.flags = 0; sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif offset += 2; length -= 2; } diff --git a/src/mares_iconhd_parser.c b/src/mares_iconhd_parser.c index 8992f64..51b1fd4 100644 --- a/src/mares_iconhd_parser.c +++ b/src/mares_iconhd_parser.c @@ -510,10 +510,14 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t return DC_STATUS_DATAFORMAT; } if (gasmix != gasmix_previous) { + sample.gasmix = gasmix; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED sample.event.type = SAMPLE_EVENT_GASCHANGE; sample.event.time = 0; sample.event.value = parser->oxygen[gasmix]; if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif gasmix_previous = gasmix; } } diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 6651519..8e52d5b 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -777,6 +777,9 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ ERROR (abstract->context, "Invalid gas mix index (%u).", gasmix); return DC_STATUS_DATAFORMAT; } + sample.gasmix = gasmix - 1; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED unsigned int o2 = parser->oxygen[gasmix - 1]; unsigned int he = parser->helium[gasmix - 1]; sample.event.type = SAMPLE_EVENT_GASCHANGE2; @@ -784,6 +787,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ sample.event.flags = 0; sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif gasmix_previous = gasmix; } diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index f5ada2b..1423e77 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -88,6 +88,20 @@ static const dc_parser_vtable_t shearwater_petrel_parser_vtable = { }; +static unsigned int +shearwater_predator_find_gasmix (shearwater_predator_parser_t *parser, unsigned int o2, unsigned int he) +{ + unsigned int i = 0; + while (i < parser->ngasmixes) { + if (o2 == parser->oxygen[i] && he == parser->helium[i]) + break; + i++; + } + + return i; +} + + dc_status_t shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int petrel) { @@ -418,11 +432,21 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal unsigned int o2 = data[offset + 7]; unsigned int he = data[offset + 8]; if (o2 != o2_previous || he != he_previous) { + unsigned int idx = shearwater_predator_find_gasmix (parser, o2, he); + if (idx >= parser->ngasmixes) { + ERROR (abstract->context, "Invalid gas mix."); + return DC_STATUS_DATAFORMAT; + } + + sample.gasmix = idx; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED sample.event.type = SAMPLE_EVENT_GASCHANGE2; sample.event.time = 0; sample.event.flags = 0; sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif o2_previous = o2; he_previous = he; } diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c index 4fd94aa..c59ac48 100644 --- a/src/suunto_d9_parser.c +++ b/src/suunto_d9_parser.c @@ -94,6 +94,19 @@ static const dc_parser_vtable_t suunto_d9_parser_vtable = { suunto_d9_parser_destroy /* destroy */ }; +static unsigned int +suunto_d9_parser_find_gasmix (suunto_d9_parser_t *parser, unsigned int o2, unsigned int he) +{ + // Find the gasmix in the list. + unsigned int i = 0; + while (i < parser->ngasmixes) { + if (o2 == parser->oxygen[i] && he == parser->helium[i]) + break; + i++; + } + + return i; +} static dc_status_t suunto_d9_parser_cache (suunto_d9_parser_t *parser) @@ -487,12 +500,16 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca ERROR (abstract->context, "Invalid initial gas mix."); return DC_STATUS_DATAFORMAT; } + sample.gasmix = parser->gasmix; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED unsigned int he = parser->helium[parser->gasmix]; unsigned int o2 = parser->oxygen[parser->gasmix]; sample.event.type = SAMPLE_EVENT_GASCHANGE2; sample.event.time = 0; sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif } // Events @@ -501,7 +518,7 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca unsigned int event = data[offset++]; unsigned int seconds, type, unknown, heading; unsigned int current, next; - unsigned int he, o2; + unsigned int he, o2, idx; unsigned int length; sample.event.type = SAMPLE_EVENT_NONE; @@ -668,10 +685,19 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca } o2 = data[offset + 0]; seconds = data[offset + 1]; + idx = suunto_d9_parser_find_gasmix(parser, o2, 0); + if (idx >= parser->ngasmixes) { + ERROR (abstract->context, "Invalid gas mix."); + return DC_STATUS_DATAFORMAT; + } + sample.gasmix = idx; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED sample.event.type = SAMPLE_EVENT_GASCHANGE; sample.event.time = seconds; sample.event.value = o2; if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif offset += 2; break; case 0x06: // Gas Change @@ -691,10 +717,19 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca } else { seconds = data[offset + 3]; } + idx = suunto_d9_parser_find_gasmix(parser, o2, he); + if (idx >= parser->ngasmixes) { + ERROR (abstract->context, "Invalid gas mix."); + return DC_STATUS_DATAFORMAT; + } + sample.gasmix = idx; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED sample.event.type = SAMPLE_EVENT_GASCHANGE2; sample.event.time = seconds; sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif offset += length; break; default: diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index 10577b2..2e31c90 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -557,19 +557,22 @@ static void sample_gas_switch_event(struct sample_data *info, unsigned short idx { suunto_eonsteel_parser_t *eon = info->eon; dc_sample_value_t sample = {0}; - int o2, he; if (idx < 1 || idx > eon->cache.ngases) return; - // Horrible, broken, gas change events - o2 = 100 * eon->cache.gasmix[idx-1].oxygen; - he = 100 * eon->cache.gasmix[idx-1].helium; + sample.gasmix = idx - 1; + if (info->callback) info->callback(DC_SAMPLE_GASMIX, sample, info->userdata); +#ifdef ENABLE_DEPRECATED + unsigned int o2 = 100 * eon->cache.gasmix[idx-1].oxygen; + unsigned int he = 100 * eon->cache.gasmix[idx-1].helium; sample.event.type = SAMPLE_EVENT_GASCHANGE2; + sample.event.time = 0; + sample.event.flags = 0; sample.event.value = o2 | (he << 16); - if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata); +#endif } /* diff --git a/src/suunto_vyper_parser.c b/src/suunto_vyper_parser.c index 946dcaf..4e2d974 100644 --- a/src/suunto_vyper_parser.c +++ b/src/suunto_vyper_parser.c @@ -59,6 +59,18 @@ static const dc_parser_vtable_t suunto_vyper_parser_vtable = { suunto_vyper_parser_destroy /* destroy */ }; +static unsigned int +suunto_vyper_parser_find_gasmix (suunto_vyper_parser_t *parser, unsigned int o2) +{ + unsigned int i = 0; + while (i < parser->ngasmixes) { + if (o2 == parser->oxygen[i]) + break; + i++; + } + + return i; +} static dc_status_t suunto_vyper_parser_cache (suunto_vyper_parser_t *parser) @@ -353,6 +365,7 @@ suunto_vyper_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t complete = 1; } else { // Event. + unsigned int o2 = 0, idx = 0; sample.event.type = SAMPLE_EVENT_NONE; sample.event.time = 0; sample.event.flags = 0; @@ -382,8 +395,22 @@ suunto_vyper_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t case 0x87: // Gas Change if (offset + 1 > size) return DC_STATUS_DATAFORMAT; + + o2 = data[offset++]; + idx = suunto_vyper_parser_find_gasmix (parser, o2); + if (idx >= parser->ngasmixes) { + ERROR (abstract->context, "Maximum number of gas mixes reached."); + return DC_STATUS_DATAFORMAT; + } + + sample.gasmix = idx; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED sample.event.type = SAMPLE_EVENT_GASCHANGE; - sample.event.value = data[offset++]; + sample.event.value = o2; +#else + sample.event.type = SAMPLE_EVENT_NONE; +#endif break; default: // Unknown WARNING (abstract->context, "Unknown event"); diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index 969c7e4..9009fbe 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -1115,6 +1115,9 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ERROR (abstract->context, "Invalid gas mix index."); return DC_STATUS_DATAFORMAT; } + sample.gasmix = idx; + if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); +#ifdef ENABLE_DEPRECATED unsigned int o2 = parser->gasmix[idx].oxygen; unsigned int he = parser->gasmix[idx].helium; sample.event.type = SAMPLE_EVENT_GASCHANGE2; @@ -1122,6 +1125,7 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t sample.event.flags = 0; sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif gasmix_previous = gasmix; } From dd779d531a19efbae21db5f21edc77a8f9bb4370 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 3 Jan 2016 20:35:57 +0100 Subject: [PATCH 04/45] Fix the date parsing for several models. To store the day (range 1 to 31) as a binary encoded value, only 5 bits are required. The extra 6th bit is part of the year. The year is also not BCD encoded. This happened to work by accident, because for a single nibble, the current implementation of the bcd2dec() function returns the binary value. --- src/oceanic_atom2_parser.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 8e52d5b..99d5602 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -251,6 +251,10 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim case VEO20: case VEO30: case DG03: + case T3A: + case T3B: + case GEO20: + case PROPLUS3: datetime->year = ((p[3] & 0xE0) >> 1) + (p[4] & 0x0F) + 2000; datetime->month = (p[4] & 0xF0) >> 4; datetime->day = p[3] & 0x1F; @@ -294,11 +298,7 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim default: datetime->year = bcd2dec (((p[3] & 0xC0) >> 2) + (p[4] & 0x0F)) + 2000; datetime->month = (p[4] & 0xF0) >> 4; - if (parser->model == T3A || parser->model == T3B || - parser->model == GEO20 || parser->model == PROPLUS3) - datetime->day = p[3] & 0x3F; - else - datetime->day = bcd2dec (p[3] & 0x3F); + datetime->day = bcd2dec (p[3] & 0x3F); datetime->hour = bcd2dec (p[1] & 0x1F); datetime->minute = bcd2dec (p[0]); break; From b5503e53fd7555cfbc5da6a582d8e60b5e10eef8 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 07:26:07 +0100 Subject: [PATCH 05/45] Add a more modular example application. The universal application works well, but is quite difficult to extend with more functionality. Therefore a new and more modular application is needed. The new dctool application will support multiple sub-commands, to carry out specific actions. Extending the application will be as easy as adding new commands. --- configure.ac | 2 + examples/Makefile.am | 14 +- examples/common.c | 66 --- examples/dctool.c | 125 ++++ examples/{common.h => dctool.h} | 23 +- examples/hw_ostc_fwupdate.c | 145 ----- examples/universal.c | 979 -------------------------------- 7 files changed, 144 insertions(+), 1210 deletions(-) delete mode 100644 examples/common.c create mode 100644 examples/dctool.c rename examples/{common.h => dctool.h} (69%) delete mode 100644 examples/hw_ostc_fwupdate.c delete mode 100644 examples/universal.c diff --git a/configure.ac b/configure.ac index 047b3f0..ca071fa 100644 --- a/configure.ac +++ b/configure.ac @@ -105,10 +105,12 @@ AM_CONDITIONAL([IRDA], [test "$irda_win32" = "yes" || test "$irda_linux" = "yes" # Checks for header files. AC_CHECK_HEADERS([linux/serial.h]) AC_CHECK_HEADERS([IOKit/serial/ioss.h]) +AC_CHECK_HEADERS([getopt.h]) # Checks for library functions. AC_FUNC_STRERROR_R AC_CHECK_FUNCS([localtime_r gmtime_r]) +AC_CHECK_FUNCS([getopt_long]) # Versioning. AC_SUBST([DC_VERSION],[dc_version]) diff --git a/examples/Makefile.am b/examples/Makefile.am index d77db45..ddbade4 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -2,12 +2,10 @@ AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include LDADD = $(top_builddir)/src/libdivecomputer.la bin_PROGRAMS = \ - universal \ - ostc-fwupdate + dctool -COMMON = common.c common.h \ - utils.c utils.h - -universal_SOURCES = universal.c $(COMMON) - -ostc_fwupdate_SOURCES = hw_ostc_fwupdate.c $(COMMON) +dctool_SOURCES = \ + dctool.h \ + dctool.c \ + utils.h \ + utils.c diff --git a/examples/common.c b/examples/common.c deleted file mode 100644 index f69e7e4..0000000 --- a/examples/common.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * libdivecomputer - * - * Copyright (C) 2011 Jef Driesen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ - -#include "common.h" -#include "utils.h" - -const char * -errmsg (dc_status_t rc) -{ - switch (rc) { - case DC_STATUS_SUCCESS: - return "Success"; - case DC_STATUS_UNSUPPORTED: - return "Unsupported operation"; - case DC_STATUS_INVALIDARGS: - return "Invalid arguments"; - case DC_STATUS_NOMEMORY: - return "Out of memory"; - case DC_STATUS_NODEVICE: - return "No device found"; - case DC_STATUS_NOACCESS: - return "Access denied"; - case DC_STATUS_IO: - return "Input/output error"; - case DC_STATUS_TIMEOUT: - return "Timeout"; - case DC_STATUS_PROTOCOL: - return "Protocol error"; - case DC_STATUS_DATAFORMAT: - return "Data format error"; - case DC_STATUS_CANCELLED: - return "Cancelled"; - default: - return "Unknown error"; - } -} - -void -logfunc (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *msg, void *userdata) -{ - const char *loglevels[] = {"NONE", "ERROR", "WARNING", "INFO", "DEBUG", "ALL"}; - - if (loglevel == DC_LOGLEVEL_ERROR || loglevel == DC_LOGLEVEL_WARNING) { - message ("%s: %s [in %s:%d (%s)]\n", loglevels[loglevel], msg, file, line, function); - } else { - message ("%s: %s\n", loglevels[loglevel], msg); - } -} diff --git a/examples/dctool.c b/examples/dctool.c new file mode 100644 index 0000000..b0b0c9c --- /dev/null +++ b/examples/dctool.c @@ -0,0 +1,125 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif + +#include "dctool.h" +#include "utils.h" + +#if defined(__GLIBC__) || defined(__MINGW32__) +#define NOPERMUTATION "+" +#define RESET 0 +#else +#define NOPERMUTATION "" +#define RESET 1 +#endif + +static const dctool_command_t *g_commands[] = { + NULL +}; + +const dctool_command_t * +dctool_command_find (const char *name) +{ + if (name == NULL) + return NULL; + + size_t i = 0; + while (g_commands[i] != NULL) { + if (strcmp(g_commands[i]->name, name) == 0) { + break; + } + i++; + } + + return g_commands[i]; +} + +int +main (int argc, char *argv[]) +{ + // Default option values. + unsigned int help = 0; + + // Parse the command-line options. + int opt = 0; + const char *optstring = NOPERMUTATION "h"; +#ifdef HAVE_GETOPT_LONG + struct option options[] = { + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0 } + }; + while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { +#else + while ((opt = getopt (argc, argv, optstring)) != -1) { +#endif + switch (opt) { + case 'h': + help = 1; + break; + default: + return EXIT_FAILURE; + } + } + + // Skip the processed arguments. + argc -= optind; + argv += optind; + optind = RESET; + + // Show help message. + if (help || argv[0] == NULL) { + printf ( + "A simple command line interface for the libdivecomputer library\n" + "\n" + "Usage:\n" + " dctool [options] []\n" + "\n" + "Options:\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help Show help message\n" +#else + " -h Show help message\n" +#endif + "\n"); + return EXIT_SUCCESS; + } + + // Try to find the command. + const dctool_command_t *command = dctool_command_find (argv[0]); + if (command == NULL) { + message ("Unknown command %s.\n", argv[0]); + return EXIT_FAILURE; + } + + // Execute the command. + return command->run (argc, argv); +} diff --git a/examples/common.h b/examples/dctool.h similarity index 69% rename from examples/common.h rename to examples/dctool.h index 4c23f1b..6443caf 100644 --- a/examples/common.h +++ b/examples/dctool.h @@ -1,7 +1,7 @@ /* * libdivecomputer * - * Copyright (C) 2011 Jef Driesen + * Copyright (C) 2015 Jef Driesen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,23 +19,22 @@ * MA 02110-1301 USA */ -#ifndef EXAMPLES_COMMON_H -#define EXAMPLES_COMMON_H - -#include -#include +#ifndef DCTOOL_H +#define DCTOOL_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -const char * -errmsg (dc_status_t rc); - -void -logfunc (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *msg, void *userdata); +typedef struct dctool_command_t { + int (*run) (int argc, char *argv[]); + const char *name; + const char *description; + const char *usage; +} dctool_command_t; #ifdef __cplusplus } #endif /* __cplusplus */ -#endif /* EXAMPLES_COMMON_H */ + +#endif /* DCTOOL_H */ diff --git a/examples/hw_ostc_fwupdate.c b/examples/hw_ostc_fwupdate.c deleted file mode 100644 index 8fa5c31..0000000 --- a/examples/hw_ostc_fwupdate.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * libdivecomputer - * - * Copyright (C) 2013 Jef Driesen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ - -#include - -#include -#include - -#include "utils.h" -#include "common.h" - -static void -event_cb (dc_device_t *device, dc_event_type_t event, const void *data, void *userdata) -{ - const dc_event_progress_t *progress = (dc_event_progress_t *) data; - - switch (event) { - case DC_EVENT_PROGRESS: - message ("Event: progress %3.2f%% (%u/%u)\n", - 100.0 * (double) progress->current / (double) progress->maximum, - progress->current, progress->maximum); - break; - default: - break; - } -} - -static dc_status_t -fwupdate (const char *name, const char *hexfile, int ostc3) -{ - dc_context_t *context = NULL; - dc_device_t *device = NULL; - dc_status_t rc = DC_STATUS_SUCCESS; - - dc_context_new (&context); - dc_context_set_loglevel (context, DC_LOGLEVEL_ALL); - dc_context_set_logfunc (context, logfunc, NULL); - - if (ostc3) { - message ("hw_ostc3_device_open\n"); - rc = hw_ostc3_device_open (&device, context, name); - } else { - message ("hw_ostc_device_open\n"); - rc = hw_ostc_device_open (&device, context, name); - } - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error opening serial port."); - dc_context_free (context); - return rc; - } - - message ("dc_device_set_events.\n"); - rc = dc_device_set_events (device, DC_EVENT_PROGRESS, event_cb, NULL); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error registering the event handler."); - dc_device_close (device); - dc_context_free (context); - return rc; - } - - if (ostc3) { - message ("hw_ostc3_device_fwupdate\n"); - rc = hw_ostc3_device_fwupdate (device, hexfile); - } else { - message ("hw_ostc_device_fwupdate\n"); - rc = hw_ostc_device_fwupdate (device, hexfile); - } - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error flashing firmware."); - dc_device_close (device); - dc_context_free (context); - return rc; - } - - message ("dc_device_close\n"); - rc = dc_device_close (device); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Cannot close device."); - dc_context_free (context); - return rc; - } - - dc_context_free (context); - - return DC_STATUS_SUCCESS; -} - - -int main(int argc, char *argv[]) -{ - message_set_logfile ("OSTC-FWUPDATE.LOG"); - -#ifdef _WIN32 - const char* name = "COM1"; -#else - const char* name = "/dev/ttyUSB0"; -#endif - const char *hexfile = NULL; - int ostc3 = 0; - - if (argc > 1) { - name = argv[1]; - } - if (argc > 2) { - hexfile = argv[2]; - } - if (argc > 3) { - if (strcmp(argv[3], "-3") == 0) { - ostc3 = 1; - } else { - ostc3 = 0; - } - } - - message ("DEVICE=%s\n", name); - message ("HEXFILE=%s\n", hexfile); - - dc_status_t a = fwupdate (name, hexfile, ostc3); - - message ("SUMMARY\n"); - message ("-------\n"); - message ("fwupdate: %s\n", errmsg (a)); - - message_set_logfile (NULL); - - return 0; -} diff --git a/examples/universal.c b/examples/universal.c deleted file mode 100644 index b4d9b47..0000000 --- a/examples/universal.c +++ /dev/null @@ -1,979 +0,0 @@ -/* - * libdivecomputer - * - * Copyright (C) 2009 Jef Driesen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ - -#include // fopen, fwrite, fclose -#include -#include -#include - -#ifndef _MSC_VER -#include -#endif - -#ifdef _MSC_VER -#define snprintf _snprintf -#define strcasecmp _stricmp -#define strncasecmp _strnicmp -#endif - -#ifdef _WIN32 -#define DC_TICKS_FORMAT "%I64d" -#else -#define DC_TICKS_FORMAT "%lld" -#endif - -#include -#include -#include - -#include "utils.h" -#include "common.h" - -static const char *g_cachedir = NULL; -static int g_cachedir_read = 1; - -typedef struct device_data_t { - dc_event_devinfo_t devinfo; - dc_event_clock_t clock; -} device_data_t; - -typedef struct dive_data_t { - dc_device_t *device; - FILE* fp; - unsigned int number; - dc_buffer_t *fingerprint; -} dive_data_t; - -typedef struct sample_data_t { - FILE* fp; - unsigned int nsamples; -} sample_data_t; - -typedef struct backend_table_t { - const char *name; - dc_family_t type; -} backend_table_t; - -static const backend_table_t g_backends[] = { - {"solution", DC_FAMILY_SUUNTO_SOLUTION}, - {"eon", DC_FAMILY_SUUNTO_EON}, - {"vyper", DC_FAMILY_SUUNTO_VYPER}, - {"vyper2", DC_FAMILY_SUUNTO_VYPER2}, - {"d9", DC_FAMILY_SUUNTO_D9}, - {"eonsteel", DC_FAMILY_SUUNTO_EONSTEEL}, - {"aladin", DC_FAMILY_UWATEC_ALADIN}, - {"memomouse", DC_FAMILY_UWATEC_MEMOMOUSE}, - {"smart", DC_FAMILY_UWATEC_SMART}, - {"meridian", DC_FAMILY_UWATEC_MERIDIAN}, - {"sensus", DC_FAMILY_REEFNET_SENSUS}, - {"sensuspro", DC_FAMILY_REEFNET_SENSUSPRO}, - {"sensusultra", DC_FAMILY_REEFNET_SENSUSULTRA}, - {"vtpro", DC_FAMILY_OCEANIC_VTPRO}, - {"veo250", DC_FAMILY_OCEANIC_VEO250}, - {"atom2", DC_FAMILY_OCEANIC_ATOM2}, - {"nemo", DC_FAMILY_MARES_NEMO}, - {"puck", DC_FAMILY_MARES_PUCK}, - {"darwin", DC_FAMILY_MARES_DARWIN}, - {"iconhd", DC_FAMILY_MARES_ICONHD}, - {"ostc", DC_FAMILY_HW_OSTC}, - {"frog", DC_FAMILY_HW_FROG}, - {"ostc3", DC_FAMILY_HW_OSTC3}, - {"edy", DC_FAMILY_CRESSI_EDY}, - {"leonardo", DC_FAMILY_CRESSI_LEONARDO}, - {"n2ition3", DC_FAMILY_ZEAGLE_N2ITION3}, - {"cobalt", DC_FAMILY_ATOMICS_COBALT}, - {"predator", DC_FAMILY_SHEARWATER_PREDATOR}, - {"petrel", DC_FAMILY_SHEARWATER_PETREL}, - {"nitekq", DC_FAMILY_DIVERITE_NITEKQ}, - {"aqualand", DC_FAMILY_CITIZEN_AQUALAND}, - {"idive", DC_FAMILY_DIVESYSTEM_IDIVE}, -}; - -static dc_family_t -lookup_type (const char *name) -{ - unsigned int nbackends = sizeof (g_backends) / sizeof (g_backends[0]); - for (unsigned int i = 0; i < nbackends; ++i) { - if (strcmp (name, g_backends[i].name) == 0) - return g_backends[i].type; - } - - return DC_FAMILY_NULL; -} - -static const char * -lookup_name (dc_family_t type) -{ - unsigned int nbackends = sizeof (g_backends) / sizeof (g_backends[0]); - for (unsigned int i = 0; i < nbackends; ++i) { - if (g_backends[i].type == type) - return g_backends[i].name; - } - - return NULL; -} - -static unsigned char -hex2dec (unsigned char value) -{ - if (value >= '0' && value <= '9') - return value - '0'; - else if (value >= 'A' && value <= 'F') - return value - 'A' + 10; - else if (value >= 'a' && value <= 'f') - return value - 'a' + 10; - else - return 0; -} - -static dc_buffer_t * -fpconvert (const char *fingerprint) -{ - // Get the length of the fingerprint data. - size_t nbytes = (fingerprint ? strlen (fingerprint) / 2 : 0); - if (nbytes == 0) - return NULL; - - // Allocate a memory buffer. - dc_buffer_t *buffer = dc_buffer_new (nbytes); - - // Convert the hexadecimal string. - for (unsigned int i = 0; i < nbytes; ++i) { - unsigned char msn = hex2dec (fingerprint[i * 2 + 0]); - unsigned char lsn = hex2dec (fingerprint[i * 2 + 1]); - unsigned char byte = (msn << 4) + lsn; - - dc_buffer_append (buffer, &byte, 1); - } - - return buffer; -} - -static dc_buffer_t * -fpread (const char *dirname, dc_family_t backend, unsigned int serial) -{ - // Build the filename. - char filename[1024] = {0}; - snprintf (filename, sizeof (filename), "%s/%s-%08X.bin", - dirname, lookup_name (backend), serial); - - // Open the fingerprint file. - FILE *fp = fopen (filename, "rb"); - if (fp == NULL) - return NULL; - - // Allocate a memory buffer. - dc_buffer_t *buffer = dc_buffer_new (0); - - // Read the entire file into the buffer. - size_t n = 0; - unsigned char block[1024] = {0}; - while ((n = fread (block, 1, sizeof (block), fp)) > 0) { - dc_buffer_append (buffer, block, n); - } - - // Close the file. - fclose (fp); - - return buffer; -} - -static void -fpwrite (dc_buffer_t *buffer, const char *dirname, dc_family_t backend, unsigned int serial) -{ - // Check the buffer size. - if (dc_buffer_get_size (buffer) == 0) - return; - - // Build the filename. - char filename[1024] = {0}; - snprintf (filename, sizeof (filename), "%s/%s-%08X.bin", - dirname, lookup_name (backend), serial); - - // Open the fingerprint file. - FILE *fp = fopen (filename, "wb"); - if (fp == NULL) - return; - - // Write the fingerprint data. - fwrite (dc_buffer_get_data (buffer), 1, dc_buffer_get_size (buffer), fp); - - // Close the file. - fclose (fp); -} - -volatile sig_atomic_t g_cancel = 0; - -void -sighandler (int signum) -{ -#ifndef _WIN32 - // Restore the default signal handler. - signal (signum, SIG_DFL); -#endif - - g_cancel = 1; -} - -static int -cancel_cb (void *userdata) -{ - return g_cancel; -} - -void -sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata) -{ - static const char *events[] = { - "none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter", - "violation", "bookmark", "surface", "safety stop", "gaschange", - "safety stop (voluntary)", "safety stop (mandatory)", "deepstop", - "ceiling (safety stop)", "floor", "divetime", "maxdepth", - "OLF", "PO2", "airtime", "rgbm", "heading", "tissue level warning", - "gaschange2"}; - static const char *decostop[] = { - "ndl", "safety", "deco", "deep"}; - - sample_data_t *sampledata = (sample_data_t *) userdata; - - switch (type) { - case DC_SAMPLE_TIME: - if (sampledata->nsamples++) - fprintf (sampledata->fp, "\n"); - fprintf (sampledata->fp, "\n"); - fprintf (sampledata->fp, " \n", value.time / 60, value.time % 60); - break; - case DC_SAMPLE_DEPTH: - fprintf (sampledata->fp, " %.2f\n", value.depth); - break; - case DC_SAMPLE_PRESSURE: - fprintf (sampledata->fp, " %.2f\n", value.pressure.tank, value.pressure.value); - break; - case DC_SAMPLE_TEMPERATURE: - fprintf (sampledata->fp, " %.2f\n", value.temperature); - break; - case DC_SAMPLE_EVENT: - if (value.event.type == SAMPLE_EVENT_GASCHANGE || value.event.type == SAMPLE_EVENT_GASCHANGE2) { - // Ignore deprecated events. - } else { - fprintf (sampledata->fp, " %s\n", - value.event.type, value.event.time, value.event.flags, value.event.value, events[value.event.type]); - } - break; - case DC_SAMPLE_RBT: - fprintf (sampledata->fp, " %u\n", value.rbt); - break; - case DC_SAMPLE_HEARTBEAT: - fprintf (sampledata->fp, " %u\n", value.heartbeat); - break; - case DC_SAMPLE_BEARING: - fprintf (sampledata->fp, " %u\n", value.bearing); - break; - case DC_SAMPLE_VENDOR: - fprintf (sampledata->fp, " ", value.vendor.type, value.vendor.size); - for (unsigned int i = 0; i < value.vendor.size; ++i) - fprintf (sampledata->fp, "%02X", ((unsigned char *) value.vendor.data)[i]); - fprintf (sampledata->fp, "\n"); - break; - case DC_SAMPLE_SETPOINT: - fprintf (sampledata->fp, " %.2f\n", value.setpoint); - break; - case DC_SAMPLE_PPO2: - fprintf (sampledata->fp, " %.2f\n", value.ppo2); - break; - case DC_SAMPLE_CNS: - fprintf (sampledata->fp, " %.1f\n", value.cns * 100.0); - break; - case DC_SAMPLE_DECO: - fprintf (sampledata->fp, " %s\n", - value.deco.time, value.deco.depth, decostop[value.deco.type]); - break; - case DC_SAMPLE_GASMIX: - fprintf (sampledata->fp, " %u\n", value.gasmix); - break; - default: - break; - } -} - - -static dc_status_t -doparse (FILE *fp, dc_device_t *device, const unsigned char data[], unsigned int size) -{ - // Create the parser. - message ("Creating the parser.\n"); - dc_parser_t *parser = NULL; - dc_status_t rc = dc_parser_new (&parser, device); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error creating the parser."); - return rc; - } - - // Register the data. - message ("Registering the data.\n"); - rc = dc_parser_set_data (parser, data, size); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error registering the data."); - dc_parser_destroy (parser); - return rc; - } - - // Parse the datetime. - message ("Parsing the datetime.\n"); - dc_datetime_t dt = {0}; - rc = dc_parser_get_datetime (parser, &dt); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the datetime."); - dc_parser_destroy (parser); - return rc; - } - - fprintf (fp, "%04i-%02i-%02i %02i:%02i:%02i\n", - dt.year, dt.month, dt.day, - dt.hour, dt.minute, dt.second); - - // Parse the divetime. - message ("Parsing the divetime.\n"); - unsigned int divetime = 0; - rc = dc_parser_get_field (parser, DC_FIELD_DIVETIME, 0, &divetime); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the divetime."); - dc_parser_destroy (parser); - return rc; - } - - fprintf (fp, "%02u:%02u\n", - divetime / 60, divetime % 60); - - // Parse the temperature. - message ("Parsing the temperature.\n"); - for (unsigned int i = 0; i < 3; ++i) { - dc_field_type_t fields[] = {DC_FIELD_TEMPERATURE_SURFACE, - DC_FIELD_TEMPERATURE_MINIMUM, - DC_FIELD_TEMPERATURE_MAXIMUM}; - const char *names[] = {"surface", "minimum", "maximum"}; - - double temperature = 0.0; - rc = dc_parser_get_field (parser, fields[i], 0, &temperature); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the temperature."); - dc_parser_destroy (parser); - return rc; - } - - if (rc != DC_STATUS_UNSUPPORTED) { - fprintf (fp, "%.1f\n", - names[i], temperature); - } - } - - // Parse the maxdepth. - message ("Parsing the maxdepth.\n"); - double maxdepth = 0.0; - rc = dc_parser_get_field (parser, DC_FIELD_MAXDEPTH, 0, &maxdepth); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the maxdepth."); - dc_parser_destroy (parser); - return rc; - } - - fprintf (fp, "%.2f\n", - maxdepth); - - // Parse the gas mixes. - message ("Parsing the gas mixes.\n"); - unsigned int ngases = 0; - rc = dc_parser_get_field (parser, DC_FIELD_GASMIX_COUNT, 0, &ngases); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the gas mix count."); - dc_parser_destroy (parser); - return rc; - } - - for (unsigned int i = 0; i < ngases; ++i) { - dc_gasmix_t gasmix = {0}; - rc = dc_parser_get_field (parser, DC_FIELD_GASMIX, i, &gasmix); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the gas mix."); - dc_parser_destroy (parser); - return rc; - } - - fprintf (fp, - "\n" - " %.1f\n" - " %.1f\n" - " %.1f\n" - "\n", - gasmix.helium * 100.0, - gasmix.oxygen * 100.0, - gasmix.nitrogen * 100.0); - } - - // Parse the tanks. - message ("Parsing the tanks.\n"); - unsigned int ntanks = 0; - rc = dc_parser_get_field (parser, DC_FIELD_TANK_COUNT, 0, &ntanks); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the tank count."); - dc_parser_destroy (parser); - return rc; - } - - for (unsigned int i = 0; i < ntanks; ++i) { - const char *names[] = {"none", "metric", "imperial"}; - - dc_tank_t tank = {0}; - rc = dc_parser_get_field (parser, DC_FIELD_TANK, i, &tank); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the tank."); - dc_parser_destroy (parser); - return rc; - } - - fprintf (fp, "\n"); - if (tank.gasmix != DC_GASMIX_UNKNOWN) { - fprintf (fp, - " %u\n", - tank.gasmix); - } - if (tank.type != DC_TANKVOLUME_NONE) { - fprintf (fp, - " %s\n" - " %.1f\n" - " %.2f\n", - names[tank.type], tank.volume, tank.workpressure); - } - fprintf (fp, - " %.2f\n" - " %.2f\n" - "\n", - tank.beginpressure, tank.endpressure); - } - - // Parse the dive mode. - message ("Parsing the dive mode.\n"); - dc_divemode_t divemode = DC_DIVEMODE_OC; - rc = dc_parser_get_field (parser, DC_FIELD_DIVEMODE, 0, &divemode); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the dive mode."); - dc_parser_destroy (parser); - return rc; - } - - if (rc != DC_STATUS_UNSUPPORTED) { - const char *names[] = {"freedive", "gauge", "oc", "cc"}; - fprintf (fp, "%s\n", - names[divemode]); - } - - // Parse the salinity. - message ("Parsing the salinity.\n"); - dc_salinity_t salinity = {DC_WATER_FRESH, 0.0}; - rc = dc_parser_get_field (parser, DC_FIELD_SALINITY, 0, &salinity); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the salinity."); - dc_parser_destroy (parser); - return rc; - } - - if (rc != DC_STATUS_UNSUPPORTED) { - fprintf (fp, "%.1f\n", - salinity.type, salinity.density); - } - - // Parse the atmospheric pressure. - message ("Parsing the atmospheric pressure.\n"); - double atmospheric = 0.0; - rc = dc_parser_get_field (parser, DC_FIELD_ATMOSPHERIC, 0, &atmospheric); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the atmospheric pressure."); - dc_parser_destroy (parser); - return rc; - } - - if (rc != DC_STATUS_UNSUPPORTED) { - fprintf (fp, "%.5f\n", - atmospheric); - } - - // Initialize the sample data. - sample_data_t sampledata = {0}; - sampledata.nsamples = 0; - sampledata.fp = fp; - - // Parse the sample data. - message ("Parsing the sample data.\n"); - rc = dc_parser_samples_foreach (parser, sample_cb, &sampledata); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error parsing the sample data."); - dc_parser_destroy (parser); - return rc; - } - - if (sampledata.nsamples) - fprintf (fp, "\n"); - - // Destroy the parser. - message ("Destroying the parser.\n"); - rc = dc_parser_destroy (parser); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error destroying the parser."); - return rc; - } - - return DC_STATUS_SUCCESS; -} - -static void -event_cb (dc_device_t *device, dc_event_type_t event, const void *data, void *userdata) -{ - const dc_event_progress_t *progress = (dc_event_progress_t *) data; - const dc_event_devinfo_t *devinfo = (dc_event_devinfo_t *) data; - const dc_event_clock_t *clock = (dc_event_clock_t *) data; - const dc_event_vendor_t *vendor = (dc_event_vendor_t *) data; - - device_data_t *devdata = (device_data_t *) userdata; - - switch (event) { - case DC_EVENT_WAITING: - message ("Event: waiting for user action\n"); - break; - case DC_EVENT_PROGRESS: - message ("Event: progress %3.2f%% (%u/%u)\n", - 100.0 * (double) progress->current / (double) progress->maximum, - progress->current, progress->maximum); - break; - case DC_EVENT_DEVINFO: - devdata->devinfo = *devinfo; - message ("Event: model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)\n", - devinfo->model, devinfo->model, - devinfo->firmware, devinfo->firmware, - devinfo->serial, devinfo->serial); - if (g_cachedir && g_cachedir_read) { - dc_buffer_t *fingerprint = fpread (g_cachedir, dc_device_get_type (device), devinfo->serial); - dc_device_set_fingerprint (device, - dc_buffer_get_data (fingerprint), - dc_buffer_get_size (fingerprint)); - dc_buffer_free (fingerprint); - } - break; - case DC_EVENT_CLOCK: - devdata->clock = *clock; - message ("Event: systime=" DC_TICKS_FORMAT ", devtime=%u\n", - clock->systime, clock->devtime); - break; - case DC_EVENT_VENDOR: - message ("Event: vendor="); - for (unsigned int i = 0; i < vendor->size; ++i) - message ("%02X", vendor->data[i]); - message ("\n"); - break; - default: - break; - } -} - -static int -dive_cb (const unsigned char *data, unsigned int size, const unsigned char *fingerprint, unsigned int fsize, void *userdata) -{ - dive_data_t *divedata = (dive_data_t *) userdata; - - divedata->number++; - - message ("Dive: number=%u, size=%u, fingerprint=", divedata->number, size); - for (unsigned int i = 0; i < fsize; ++i) - message ("%02X", fingerprint[i]); - message ("\n"); - - if (divedata->number == 1) { - divedata->fingerprint = dc_buffer_new (fsize); - dc_buffer_append (divedata->fingerprint, fingerprint, fsize); - } - - if (divedata->fp) { - fprintf (divedata->fp, "\n%u\n%u\n", divedata->number, size); - for (unsigned int i = 0; i < fsize; ++i) - fprintf (divedata->fp, "%02X", fingerprint[i]); - fprintf (divedata->fp, "\n"); - - doparse (divedata->fp, divedata->device, data, size); - - fprintf (divedata->fp, "\n"); - } - - return 1; -} - - -static void -usage (const char *filename) -{ -#ifndef _MSC_VER - fprintf (stderr, "Usage:\n\n"); - fprintf (stderr, " %s [options] devname\n\n", filename); - fprintf (stderr, "Options:\n\n"); - fprintf (stderr, " -n name Set device name (required).\n"); - fprintf (stderr, " -b name Set backend name (required).\n"); - fprintf (stderr, " -t model Set model code.\n"); - fprintf (stderr, " -f hexdata Set fingerprint data.\n"); - fprintf (stderr, " -l logfile Set logfile.\n"); - fprintf (stderr, " -d filename Download dives.\n"); - fprintf (stderr, " -m filename Download memory dump.\n"); - fprintf (stderr, " -c cachedir Set cache directory.\n"); - fprintf (stderr, " -h Show this help message.\n\n"); -#else - fprintf (stderr, "Usage:\n\n"); - fprintf (stderr, " %s backend devname\n\n", filename); -#endif - - fprintf (stderr, "Supported backends:\n\n"); - unsigned int nbackends = sizeof (g_backends) / sizeof (g_backends[0]); - for (unsigned int i = 0; i < nbackends; ++i) { - fprintf (stderr, "%s", g_backends[i].name); - if (i != nbackends - 1) - fprintf (stderr, ", "); - else - fprintf (stderr, "\n\n"); - } - - fprintf (stderr, "Supported devices:\n\n"); - dc_iterator_t *iterator = NULL; - dc_descriptor_t *descriptor = NULL; - dc_descriptor_iterator (&iterator); - while (dc_iterator_next (iterator, &descriptor) == DC_STATUS_SUCCESS) { - fprintf (stderr, " %s %s\n", - dc_descriptor_get_vendor (descriptor), - dc_descriptor_get_product (descriptor)); - dc_descriptor_free (descriptor); - } - dc_iterator_free (iterator); -} - - -static dc_status_t -search (dc_descriptor_t **out, const char *name, dc_family_t backend, unsigned int model) -{ - dc_status_t rc = DC_STATUS_SUCCESS; - - dc_iterator_t *iterator = NULL; - rc = dc_descriptor_iterator (&iterator); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error creating the device descriptor iterator."); - return rc; - } - - dc_descriptor_t *descriptor = NULL, *current = NULL; - while ((rc = dc_iterator_next (iterator, &descriptor)) == DC_STATUS_SUCCESS) { - if (name) { - const char *vendor = dc_descriptor_get_vendor (descriptor); - const char *product = dc_descriptor_get_product (descriptor); - - size_t n = strlen (vendor); - if (strncasecmp (name, vendor, n) == 0 && name[n] == ' ' && - strcasecmp (name + n + 1, product) == 0) - { - current = descriptor; - break; - } else if (strcasecmp (name, product) == 0) { - current = descriptor; - break; - } - } else { - if (backend == dc_descriptor_get_type (descriptor)) { - if (model == dc_descriptor_get_model (descriptor)) { - // Exact match found. Return immediately. - dc_descriptor_free (current); - current = descriptor; - break; - } else { - // Possible match found. Keep searching for an exact match. - // If no exact match is found, the first match is returned. - if (current == NULL) { - current = descriptor; - descriptor = NULL; - } - } - } - } - - dc_descriptor_free (descriptor); - } - - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_DONE) { - dc_descriptor_free (current); - dc_iterator_free (iterator); - WARNING ("Error iterating the device descriptors."); - return rc; - } - - dc_iterator_free (iterator); - - *out = current; - - return DC_STATUS_SUCCESS; -} - - -static dc_status_t -dowork (dc_context_t *context, dc_descriptor_t *descriptor, const char *devname, const char *rawfile, const char *xmlfile, int memory, int dives, dc_buffer_t *fingerprint) -{ - dc_status_t rc = DC_STATUS_SUCCESS; - - // Initialize the device data. - device_data_t devdata = {{0}}; - - // Open the device. - message ("Opening the device (%s %s, %s).\n", - dc_descriptor_get_vendor (descriptor), - dc_descriptor_get_product (descriptor), - devname ? devname : "null"); - dc_device_t *device = NULL; - rc = dc_device_open (&device, context, descriptor, devname); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error opening device."); - return rc; - } - - // Register the event handler. - message ("Registering the event handler.\n"); - int events = DC_EVENT_WAITING | DC_EVENT_PROGRESS | DC_EVENT_DEVINFO | DC_EVENT_CLOCK | DC_EVENT_VENDOR; - rc = dc_device_set_events (device, events, event_cb, &devdata); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error registering the event handler."); - dc_device_close (device); - return rc; - } - - // Register the cancellation handler. - message ("Registering the cancellation handler.\n"); - rc = dc_device_set_cancel (device, cancel_cb, NULL); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error registering the cancellation handler."); - dc_device_close (device); - return rc; - } - - // Register the fingerprint data. - if (fingerprint) { - message ("Registering the fingerprint data.\n"); - rc = dc_device_set_fingerprint (device, dc_buffer_get_data (fingerprint), dc_buffer_get_size (fingerprint)); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error registering the fingerprint data."); - dc_device_close (device); - return rc; - } - } - - if (memory) { - // Allocate a memory buffer. - dc_buffer_t *buffer = dc_buffer_new (0); - - // Download the memory dump. - message ("Downloading the memory dump.\n"); - rc = dc_device_dump (device, buffer); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error downloading the memory dump."); - dc_buffer_free (buffer); - dc_device_close (device); - return rc; - } - - // Write the memory dump to disk. - FILE* fp = fopen (rawfile, "wb"); - if (fp != NULL) { - fwrite (dc_buffer_get_data (buffer), 1, dc_buffer_get_size (buffer), fp); - fclose (fp); - } - - // Free the memory buffer. - dc_buffer_free (buffer); - } - - if (dives) { - // Initialize the dive data. - dive_data_t divedata = {0}; - divedata.device = device; - divedata.fingerprint = NULL; - divedata.number = 0; - - // Open the output file. - divedata.fp = fopen (xmlfile, "w"); - - if (divedata.fp) { - fprintf (divedata.fp, "\n"); - } - - // Download the dives. - message ("Downloading the dives.\n"); - rc = dc_device_foreach (device, dive_cb, &divedata); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error downloading the dives."); - dc_buffer_free (divedata.fingerprint); - if (divedata.fp) fclose (divedata.fp); - dc_device_close (device); - return rc; - } - - if (divedata.fp) { - fprintf (divedata.fp, "\n"); - } - - // Store the fingerprint data. - if (g_cachedir) { - fpwrite (divedata.fingerprint, g_cachedir, dc_device_get_type (device), devdata.devinfo.serial); - } - - // Free the fingerprint buffer. - dc_buffer_free (divedata.fingerprint); - - // Close the output file. - if (divedata.fp) fclose (divedata.fp); - } - - // Close the device. - message ("Closing the device.\n"); - rc = dc_device_close (device); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error closing the device."); - return rc; - } - - return DC_STATUS_SUCCESS; -} - - -int -main (int argc, char *argv[]) -{ - // Default values. - dc_family_t backend = DC_FAMILY_NULL; - dc_loglevel_t loglevel = DC_LOGLEVEL_WARNING; - const char *name = NULL; - const char *logfile = "output.log"; - const char *rawfile = "output.bin"; - const char *xmlfile = "output.xml"; - const char *devname = NULL; - const char *fingerprint = NULL; - unsigned int model = 0; - int memory = 0, dives = 0; - -#ifndef _MSC_VER - // Parse command-line options. - int opt = 0; - while ((opt = getopt (argc, argv, "n:b:t:f:l:m:d:c:vh")) != -1) { - switch (opt) { - case 'n': - name = optarg; - break; - case 'b': - backend = lookup_type (optarg); - break; - case 't': - model = strtoul (optarg, NULL, 0); - break; - case 'f': - fingerprint = optarg; - g_cachedir_read = 0; - break; - case 'l': - logfile = optarg; - break; - case 'v': - loglevel++; - break; - case 'm': - memory = 1; - rawfile = optarg; - break; - case 'd': - dives = 1; - xmlfile = optarg; - break; - case 'c': - g_cachedir = optarg; - break; - case '?': - case 'h': - default: - usage (argv[0]); - return EXIT_FAILURE; - } - } - - if (optind < argc) - devname = argv[optind]; -#else - if (argc > 1) - backend = lookup_type (argv[1]); - - if (argc > 2) - devname = argv[2]; -#endif - - // Set the default action. - if (!memory && !dives) { - memory = 1; - dives = 1; - } - - signal (SIGINT, sighandler); - - message_set_logfile (logfile); - - dc_context_t *context = NULL; - dc_status_t rc = dc_context_new (&context); - if (rc != DC_STATUS_SUCCESS) { - message_set_logfile (NULL); - return EXIT_FAILURE; - } - - dc_context_set_loglevel (context, loglevel); - dc_context_set_logfunc (context, logfunc, NULL); - - /* Search for a matching device descriptor. */ - dc_descriptor_t *descriptor = NULL; - rc = search (&descriptor, name, backend, model); - if (rc != DC_STATUS_SUCCESS) { - message_set_logfile (NULL); - return EXIT_FAILURE; - } - - /* Fail if no device descriptor found. */ - if (descriptor == NULL) { - WARNING ("No matching device found."); - usage (argv[0]); - message_set_logfile (NULL); - return EXIT_FAILURE; - } - - dc_buffer_t *fp = fpconvert (fingerprint); - rc = dowork (context, descriptor, devname, rawfile, xmlfile, memory, dives, fp); - dc_buffer_free (fp); - message ("Result: %s\n", errmsg (rc)); - - dc_descriptor_free (descriptor); - dc_context_free (context); - - message_set_logfile (NULL); - - return rc != DC_STATUS_SUCCESS ? EXIT_FAILURE : EXIT_SUCCESS; -} From 689e1f1f5584467465b5c16610bec6bbf59df9a7 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 07:30:48 +0100 Subject: [PATCH 06/45] Change the format for error and warning messages. Use the same format as used for printing the error and warning messages from libdivecomputer itself. --- examples/utils.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/utils.h b/examples/utils.h index 7562beb..da8a65b 100644 --- a/examples/utils.h +++ b/examples/utils.h @@ -26,13 +26,20 @@ extern "C" { #endif /* __cplusplus */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) +#define FUNCTION __func__ +#else +#define FUNCTION __FUNCTION__ +#endif + #if defined(__GNUC__) #define ATTR_FORMAT_PRINTF(a,b) __attribute__((format(printf, a, b))) #else #define ATTR_FORMAT_PRINTF(a,b) #endif -#define WARNING(expr) message ("%s:%d: %s\n", __FILE__, __LINE__, expr) +#define WARNING(expr) message("WARNING: %s [in %s:%d (%s)]\n", expr, __FILE__, __LINE__, FUNCTION) +#define ERROR(expr) message("ERROR: %s [in %s:%d (%s)]\n", expr, __FILE__, __LINE__, FUNCTION) int message (const char* fmt, ...) ATTR_FORMAT_PRINTF(1, 2); From 3c57060d95523347cfe5a6f70b01a50058b892d2 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 07:46:52 +0100 Subject: [PATCH 07/45] Setup the library context. --- examples/dctool.c | 63 ++++++++++++++++++++++++++++++++++++++++++++--- examples/dctool.h | 4 ++- 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/examples/dctool.c b/examples/dctool.c index b0b0c9c..501e33a 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -63,18 +63,39 @@ dctool_command_find (const char *name) return g_commands[i]; } +static void +logfunc (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *msg, void *userdata) +{ + const char *loglevels[] = {"NONE", "ERROR", "WARNING", "INFO", "DEBUG", "ALL"}; + + if (loglevel == DC_LOGLEVEL_ERROR || loglevel == DC_LOGLEVEL_WARNING) { + message ("%s: %s [in %s:%d (%s)]\n", loglevels[loglevel], msg, file, line, function); + } else { + message ("%s: %s\n", loglevels[loglevel], msg); + } +} + int main (int argc, char *argv[]) { + int exitcode = EXIT_SUCCESS; + dc_status_t status = DC_STATUS_SUCCESS; + dc_context_t *context = NULL; + // Default option values. unsigned int help = 0; + dc_loglevel_t loglevel = DC_LOGLEVEL_WARNING; + const char *logfile = NULL; // Parse the command-line options. int opt = 0; - const char *optstring = NOPERMUTATION "h"; + const char *optstring = NOPERMUTATION "hl:qv"; #ifdef HAVE_GETOPT_LONG struct option options[] = { {"help", no_argument, 0, 'h'}, + {"logfile", required_argument, 0, 'l'}, + {"quiet", no_argument, 0, 'q'}, + {"verbose", no_argument, 0, 'v'}, {0, 0, 0, 0 } }; while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { @@ -85,6 +106,15 @@ main (int argc, char *argv[]) case 'h': help = 1; break; + case 'l': + logfile = optarg; + break; + case 'q': + loglevel = DC_LOGLEVEL_NONE; + break; + case 'v': + loglevel++; + break; default: return EXIT_FAILURE; } @@ -105,9 +135,15 @@ main (int argc, char *argv[]) "\n" "Options:\n" #ifdef HAVE_GETOPT_LONG - " -h, --help Show help message\n" + " -h, --help Show help message\n" + " -l, --logfile Logfile\n" + " -q, --quiet Quiet mode\n" + " -v, --verbose Verbose mode\n" #else - " -h Show help message\n" + " -h Show help message\n" + " -l Logfile\n" + " -q Quiet mode\n" + " -v Verbose mode\n" #endif "\n"); return EXIT_SUCCESS; @@ -120,6 +156,25 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } + // Initialize the logfile. + message_set_logfile (logfile); + + // Initialize a library context. + status = dc_context_new (&context); + if (status != DC_STATUS_SUCCESS) { + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Setup the logging. + dc_context_set_loglevel (context, loglevel); + dc_context_set_logfunc (context, logfunc, NULL); + // Execute the command. - return command->run (argc, argv); + exitcode = command->run (argc, argv, context); + +cleanup: + dc_context_free (context); + message_set_logfile (NULL); + return exitcode; } diff --git a/examples/dctool.h b/examples/dctool.h index 6443caf..db4f527 100644 --- a/examples/dctool.h +++ b/examples/dctool.h @@ -22,12 +22,14 @@ #ifndef DCTOOL_H #define DCTOOL_H +#include + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef struct dctool_command_t { - int (*run) (int argc, char *argv[]); + int (*run) (int argc, char *argv[], dc_context_t *context); const char *name; const char *description; const char *usage; From f0e5edc50b042019d05849725c1a10946b1367ed Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 07:51:17 +0100 Subject: [PATCH 08/45] Setup the device descriptor. --- examples/Makefile.am | 2 + examples/common.c | 152 +++++++++++++++++++++++++++++++++++++++++++ examples/common.h | 45 +++++++++++++ examples/dctool.c | 60 ++++++++++++++++- examples/dctool.h | 9 ++- 5 files changed, 265 insertions(+), 3 deletions(-) create mode 100644 examples/common.c create mode 100644 examples/common.h diff --git a/examples/Makefile.am b/examples/Makefile.am index ddbade4..29f4bb6 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -5,6 +5,8 @@ bin_PROGRAMS = \ dctool dctool_SOURCES = \ + common.h \ + common.c \ dctool.h \ dctool.c \ utils.h \ diff --git a/examples/common.c b/examples/common.c new file mode 100644 index 0000000..6cb0867 --- /dev/null +++ b/examples/common.c @@ -0,0 +1,152 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include + +#include "common.h" +#include "utils.h" + +#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array)) + +typedef struct backend_table_t { + const char *name; + dc_family_t type; +} backend_table_t; + +static const backend_table_t g_backends[] = { + {"solution", DC_FAMILY_SUUNTO_SOLUTION}, + {"eon", DC_FAMILY_SUUNTO_EON}, + {"vyper", DC_FAMILY_SUUNTO_VYPER}, + {"vyper2", DC_FAMILY_SUUNTO_VYPER2}, + {"d9", DC_FAMILY_SUUNTO_D9}, + {"eonsteel", DC_FAMILY_SUUNTO_EONSTEEL}, + {"aladin", DC_FAMILY_UWATEC_ALADIN}, + {"memomouse", DC_FAMILY_UWATEC_MEMOMOUSE}, + {"smart", DC_FAMILY_UWATEC_SMART}, + {"meridian", DC_FAMILY_UWATEC_MERIDIAN}, + {"sensus", DC_FAMILY_REEFNET_SENSUS}, + {"sensuspro", DC_FAMILY_REEFNET_SENSUSPRO}, + {"sensusultra", DC_FAMILY_REEFNET_SENSUSULTRA}, + {"vtpro", DC_FAMILY_OCEANIC_VTPRO}, + {"veo250", DC_FAMILY_OCEANIC_VEO250}, + {"atom2", DC_FAMILY_OCEANIC_ATOM2}, + {"nemo", DC_FAMILY_MARES_NEMO}, + {"puck", DC_FAMILY_MARES_PUCK}, + {"darwin", DC_FAMILY_MARES_DARWIN}, + {"iconhd", DC_FAMILY_MARES_ICONHD}, + {"ostc", DC_FAMILY_HW_OSTC}, + {"frog", DC_FAMILY_HW_FROG}, + {"ostc3", DC_FAMILY_HW_OSTC3}, + {"edy", DC_FAMILY_CRESSI_EDY}, + {"leonardo", DC_FAMILY_CRESSI_LEONARDO}, + {"n2ition3", DC_FAMILY_ZEAGLE_N2ITION3}, + {"cobalt", DC_FAMILY_ATOMICS_COBALT}, + {"predator", DC_FAMILY_SHEARWATER_PREDATOR}, + {"petrel", DC_FAMILY_SHEARWATER_PETREL}, + {"nitekq", DC_FAMILY_DIVERITE_NITEKQ}, + {"aqualand", DC_FAMILY_CITIZEN_AQUALAND}, + {"idive", DC_FAMILY_DIVESYSTEM_IDIVE}, +}; + +dc_family_t +dctool_family_type (const char *name) +{ + for (unsigned int i = 0; i < C_ARRAY_SIZE (g_backends); ++i) { + if (strcmp (name, g_backends[i].name) == 0) + return g_backends[i].type; + } + + return DC_FAMILY_NULL; +} + +const char * +dctool_family_name (dc_family_t type) +{ + for (unsigned int i = 0; i < C_ARRAY_SIZE (g_backends); ++i) { + if (g_backends[i].type == type) + return g_backends[i].name; + } + + return NULL; +} + +dc_status_t +dctool_descriptor_search (dc_descriptor_t **out, const char *name, dc_family_t family, unsigned int model) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + + dc_iterator_t *iterator = NULL; + rc = dc_descriptor_iterator (&iterator); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error creating the device descriptor iterator."); + return rc; + } + + dc_descriptor_t *descriptor = NULL, *current = NULL; + while ((rc = dc_iterator_next (iterator, &descriptor)) == DC_STATUS_SUCCESS) { + if (name) { + const char *vendor = dc_descriptor_get_vendor (descriptor); + const char *product = dc_descriptor_get_product (descriptor); + + size_t n = strlen (vendor); + if (strncasecmp (name, vendor, n) == 0 && name[n] == ' ' && + strcasecmp (name + n + 1, product) == 0) + { + current = descriptor; + break; + } else if (strcasecmp (name, product) == 0) { + current = descriptor; + break; + } + } else { + if (family == dc_descriptor_get_type (descriptor)) { + if (model == dc_descriptor_get_model (descriptor)) { + // Exact match found. Return immediately. + dc_descriptor_free (current); + current = descriptor; + break; + } else { + // Possible match found. Keep searching for an exact match. + // If no exact match is found, the first match is returned. + if (current == NULL) { + current = descriptor; + descriptor = NULL; + } + } + } + } + + dc_descriptor_free (descriptor); + } + + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_DONE) { + dc_descriptor_free (current); + dc_iterator_free (iterator); + ERROR ("Error iterating the device descriptors."); + return rc; + } + + dc_iterator_free (iterator); + + *out = current; + + return DC_STATUS_SUCCESS; +} diff --git a/examples/common.h b/examples/common.h new file mode 100644 index 0000000..8393fd6 --- /dev/null +++ b/examples/common.h @@ -0,0 +1,45 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef DCTOOL_COMMON_H +#define DCTOOL_COMMON_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +dc_family_t +dctool_family_type (const char *name); + +const char * +dctool_family_name (dc_family_t type); + +dc_status_t +dctool_descriptor_search (dc_descriptor_t **out, const char *name, dc_family_t family, unsigned int model); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DCTOOL_COMMON_H */ diff --git a/examples/dctool.c b/examples/dctool.c index 501e33a..48f3687 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -31,6 +31,10 @@ #include #endif +#include +#include + +#include "common.h" #include "dctool.h" #include "utils.h" @@ -81,18 +85,25 @@ main (int argc, char *argv[]) int exitcode = EXIT_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS; dc_context_t *context = NULL; + dc_descriptor_t *descriptor = NULL; // Default option values. unsigned int help = 0; dc_loglevel_t loglevel = DC_LOGLEVEL_WARNING; const char *logfile = NULL; + const char *device = NULL; + dc_family_t family = DC_FAMILY_NULL; + unsigned int model = 0; // Parse the command-line options. int opt = 0; - const char *optstring = NOPERMUTATION "hl:qv"; + const char *optstring = NOPERMUTATION "hd:f:m:l:qv"; #ifdef HAVE_GETOPT_LONG struct option options[] = { {"help", no_argument, 0, 'h'}, + {"device", required_argument, 0, 'd'}, + {"family", required_argument, 0, 'f'}, + {"model", required_argument, 0, 'm'}, {"logfile", required_argument, 0, 'l'}, {"quiet", no_argument, 0, 'q'}, {"verbose", no_argument, 0, 'v'}, @@ -106,6 +117,15 @@ main (int argc, char *argv[]) case 'h': help = 1; break; + case 'd': + device = optarg; + break; + case 'f': + family = dctool_family_type (optarg); + break; + case 'm': + model = strtoul (optarg, NULL, 0); + break; case 'l': logfile = optarg; break; @@ -136,11 +156,17 @@ main (int argc, char *argv[]) "Options:\n" #ifdef HAVE_GETOPT_LONG " -h, --help Show help message\n" + " -d, --device Device name\n" + " -f, --family Device family type\n" + " -m, --model Device model number\n" " -l, --logfile Logfile\n" " -q, --quiet Quiet mode\n" " -v, --verbose Verbose mode\n" #else " -h Show help message\n" + " -d Device name\n" + " -f Family type\n" + " -m Model number\n" " -l Logfile\n" " -q Quiet mode\n" " -v Verbose mode\n" @@ -170,10 +196,40 @@ main (int argc, char *argv[]) dc_context_set_loglevel (context, loglevel); dc_context_set_logfunc (context, logfunc, NULL); + if (command->config & DCTOOL_CONFIG_DESCRIPTOR) { + // Check mandatory arguments. + if (device == NULL && family == DC_FAMILY_NULL) { + message ("No device name or family type specified.\n"); + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Search for a matching device descriptor. + status = dctool_descriptor_search (&descriptor, device, family, model); + if (status != DC_STATUS_SUCCESS) { + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Fail if no device descriptor found. + if (descriptor == NULL) { + if (device) { + message ("No supported device found: %s\n", + device); + } else { + message ("No supported device found: %s, 0x%X\n", + dctool_family_name (family), model); + } + exitcode = EXIT_FAILURE; + goto cleanup; + } + } + // Execute the command. - exitcode = command->run (argc, argv, context); + exitcode = command->run (argc, argv, context, descriptor); cleanup: + dc_descriptor_free (descriptor); dc_context_free (context); message_set_logfile (NULL); return exitcode; diff --git a/examples/dctool.h b/examples/dctool.h index db4f527..b091c83 100644 --- a/examples/dctool.h +++ b/examples/dctool.h @@ -23,13 +23,20 @@ #define DCTOOL_H #include +#include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ +typedef enum dctool_config_t { + DCTOOL_CONFIG_NONE = 0, + DCTOOL_CONFIG_DESCRIPTOR = 1, +} dctool_config_t; + typedef struct dctool_command_t { - int (*run) (int argc, char *argv[], dc_context_t *context); + int (*run) (int argc, char *argv[], dc_context_t *context, dc_descriptor_t *descriptor); + unsigned int config; const char *name; const char *description; const char *usage; From 28d87592945acf85e03ffeb948728773b9ea2d6d Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 08:21:34 +0100 Subject: [PATCH 09/45] Setup the cancel signal handler. --- examples/dctool.c | 23 +++++++++++++++++++++++ examples/dctool.h | 3 +++ 2 files changed, 26 insertions(+) diff --git a/examples/dctool.c b/examples/dctool.c index 48f3687..0bc3c55 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef HAVE_GETOPT_H #include #endif @@ -50,6 +51,8 @@ static const dctool_command_t *g_commands[] = { NULL }; +static volatile sig_atomic_t g_cancel = 0; + const dctool_command_t * dctool_command_find (const char *name) { @@ -67,6 +70,23 @@ dctool_command_find (const char *name) return g_commands[i]; } +int +dctool_cancel_cb (void *userdata) +{ + return g_cancel; +} + +static void +sighandler (int signum) +{ +#ifndef _WIN32 + // Restore the default signal handler. + signal (signum, SIG_DFL); +#endif + + g_cancel = 1; +} + static void logfunc (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *msg, void *userdata) { @@ -182,6 +202,9 @@ main (int argc, char *argv[]) return EXIT_FAILURE; } + // Setup the cancel signal handler. + signal (SIGINT, sighandler); + // Initialize the logfile. message_set_logfile (logfile); diff --git a/examples/dctool.h b/examples/dctool.h index b091c83..f8a08ac 100644 --- a/examples/dctool.h +++ b/examples/dctool.h @@ -42,6 +42,9 @@ typedef struct dctool_command_t { const char *usage; } dctool_command_t; +int +dctool_cancel_cb (void *userdata); + #ifdef __cplusplus } #endif /* __cplusplus */ From 655e9ad312ac68521dc219145b38825ca6a6f027 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 08:48:02 +0100 Subject: [PATCH 10/45] Add a default event handler. --- examples/common.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ examples/common.h | 3 +++ 2 files changed, 47 insertions(+) diff --git a/examples/common.c b/examples/common.c index 6cb0867..f892120 100644 --- a/examples/common.c +++ b/examples/common.c @@ -24,6 +24,12 @@ #include "common.h" #include "utils.h" +#ifdef _WIN32 +#define DC_TICKS_FORMAT "%I64d" +#else +#define DC_TICKS_FORMAT "%lld" +#endif + #define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array)) typedef struct backend_table_t { @@ -88,6 +94,44 @@ dctool_family_name (dc_family_t type) return NULL; } +void +dctool_event_cb (dc_device_t *device, dc_event_type_t event, const void *data, void *userdata) +{ + const dc_event_progress_t *progress = (const dc_event_progress_t *) data; + const dc_event_devinfo_t *devinfo = (const dc_event_devinfo_t *) data; + const dc_event_clock_t *clock = (const dc_event_clock_t *) data; + const dc_event_vendor_t *vendor = (const dc_event_vendor_t *) data; + + switch (event) { + case DC_EVENT_WAITING: + message ("Event: waiting for user action\n"); + break; + case DC_EVENT_PROGRESS: + message ("Event: progress %3.2f%% (%u/%u)\n", + 100.0 * (double) progress->current / (double) progress->maximum, + progress->current, progress->maximum); + break; + case DC_EVENT_DEVINFO: + message ("Event: model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)\n", + devinfo->model, devinfo->model, + devinfo->firmware, devinfo->firmware, + devinfo->serial, devinfo->serial); + break; + case DC_EVENT_CLOCK: + message ("Event: systime=" DC_TICKS_FORMAT ", devtime=%u\n", + clock->systime, clock->devtime); + break; + case DC_EVENT_VENDOR: + message ("Event: vendor="); + for (unsigned int i = 0; i < vendor->size; ++i) + message ("%02X", vendor->data[i]); + message ("\n"); + break; + default: + break; + } +} + dc_status_t dctool_descriptor_search (dc_descriptor_t **out, const char *name, dc_family_t family, unsigned int model) { diff --git a/examples/common.h b/examples/common.h index 8393fd6..1aa19fb 100644 --- a/examples/common.h +++ b/examples/common.h @@ -36,6 +36,9 @@ dctool_family_type (const char *name); const char * dctool_family_name (dc_family_t type); +void +dctool_event_cb (dc_device_t *device, dc_event_type_t event, const void *data, void *userdata); + dc_status_t dctool_descriptor_search (dc_descriptor_t **out, const char *name, dc_family_t family, unsigned int model); From 5188f5c25f88136625326d10847e18b5feff8ee6 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 08:55:04 +0100 Subject: [PATCH 11/45] Add a helper function for translating status codes. --- examples/common.c | 31 +++++++++++++++++++++++++++++++ examples/common.h | 3 +++ 2 files changed, 34 insertions(+) diff --git a/examples/common.c b/examples/common.c index f892120..d329635 100644 --- a/examples/common.c +++ b/examples/common.c @@ -72,6 +72,37 @@ static const backend_table_t g_backends[] = { {"idive", DC_FAMILY_DIVESYSTEM_IDIVE}, }; +const char * +dctool_errmsg (dc_status_t status) +{ + switch (status) { + case DC_STATUS_SUCCESS: + return "Success"; + case DC_STATUS_UNSUPPORTED: + return "Unsupported operation"; + case DC_STATUS_INVALIDARGS: + return "Invalid arguments"; + case DC_STATUS_NOMEMORY: + return "Out of memory"; + case DC_STATUS_NODEVICE: + return "No device found"; + case DC_STATUS_NOACCESS: + return "Access denied"; + case DC_STATUS_IO: + return "Input/output error"; + case DC_STATUS_TIMEOUT: + return "Timeout"; + case DC_STATUS_PROTOCOL: + return "Protocol error"; + case DC_STATUS_DATAFORMAT: + return "Data format error"; + case DC_STATUS_CANCELLED: + return "Cancelled"; + default: + return "Unknown error"; + } +} + dc_family_t dctool_family_type (const char *name) { diff --git a/examples/common.h b/examples/common.h index 1aa19fb..09f5524 100644 --- a/examples/common.h +++ b/examples/common.h @@ -30,6 +30,9 @@ extern "C" { #endif /* __cplusplus */ +const char * +dctool_errmsg (dc_status_t status); + dc_family_t dctool_family_type (const char *name); From 8f61648a39f8341bbc9e4980d2ebd0c8349c770a Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 09:00:06 +0100 Subject: [PATCH 12/45] Add helper functions for reading/writing binary files. --- examples/common.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++ examples/common.h | 6 +++++ 2 files changed, 71 insertions(+) diff --git a/examples/common.c b/examples/common.c index d329635..ee552cd 100644 --- a/examples/common.c +++ b/examples/common.c @@ -20,6 +20,12 @@ */ #include +#include + +#ifdef _WIN32 +#include +#include +#endif #include "common.h" #include "utils.h" @@ -225,3 +231,62 @@ dctool_descriptor_search (dc_descriptor_t **out, const char *name, dc_family_t f return DC_STATUS_SUCCESS; } + +void +dctool_file_write (const char *filename, dc_buffer_t *buffer) +{ + FILE *fp = NULL; + + // Open the file. + if (filename) { + fp = fopen (filename, "wb"); + } else { + fp = stdout; +#ifdef _WIN32 + // Change from text mode to binary mode. + _setmode (_fileno (fp), _O_BINARY); +#endif + } + if (fp == NULL) + return; + + // Write the entire buffer to the file. + fwrite (dc_buffer_get_data (buffer), 1, dc_buffer_get_size (buffer), fp); + + // Close the file. + fclose (fp); +} + +dc_buffer_t * +dctool_file_read (const char *filename) +{ + FILE *fp = NULL; + + // Open the file. + if (filename) { + fp = fopen (filename, "rb"); + } else { + fp = stdin; +#ifdef _WIN32 + // Change from text mode to binary mode. + _setmode (_fileno (fp), _O_BINARY); +#endif + } + if (fp == NULL) + return NULL; + + // Allocate a memory buffer. + dc_buffer_t *buffer = dc_buffer_new (0); + + // Read the entire file into the buffer. + size_t n = 0; + unsigned char block[1024] = {0}; + while ((n = fread (block, 1, sizeof (block), fp)) > 0) { + dc_buffer_append (buffer, block, n); + } + + // Close the file. + fclose (fp); + + return buffer; +} diff --git a/examples/common.h b/examples/common.h index 09f5524..55dbb91 100644 --- a/examples/common.h +++ b/examples/common.h @@ -45,6 +45,12 @@ dctool_event_cb (dc_device_t *device, dc_event_type_t event, const void *data, v dc_status_t dctool_descriptor_search (dc_descriptor_t **out, const char *name, dc_family_t family, unsigned int model); +void +dctool_file_write (const char *filename, dc_buffer_t *buffer); + +dc_buffer_t * +dctool_file_read (const char *filename); + #ifdef __cplusplus } #endif /* __cplusplus */ From 57a54f824c460d224ab451893863df0fddda5111 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 14:24:40 +0100 Subject: [PATCH 13/45] Add helper functions for converting hexadecimal data. --- examples/common.c | 36 ++++++++++++++++++++++++++++++++++++ examples/common.h | 3 +++ 2 files changed, 39 insertions(+) diff --git a/examples/common.c b/examples/common.c index ee552cd..fb7f73e 100644 --- a/examples/common.c +++ b/examples/common.c @@ -232,6 +232,42 @@ dctool_descriptor_search (dc_descriptor_t **out, const char *name, dc_family_t f return DC_STATUS_SUCCESS; } +static unsigned char +hex2dec (unsigned char value) +{ + if (value >= '0' && value <= '9') + return value - '0'; + else if (value >= 'A' && value <= 'F') + return value - 'A' + 10; + else if (value >= 'a' && value <= 'f') + return value - 'a' + 10; + else + return 0; +} + +dc_buffer_t * +dctool_convert_hex2bin (const char *str) +{ + // Get the length of the fingerprint data. + size_t nbytes = (str ? strlen (str) / 2 : 0); + if (nbytes == 0) + return NULL; + + // Allocate a memory buffer. + dc_buffer_t *buffer = dc_buffer_new (nbytes); + + // Convert the hexadecimal string. + for (unsigned int i = 0; i < nbytes; ++i) { + unsigned char msn = hex2dec (str[i * 2 + 0]); + unsigned char lsn = hex2dec (str[i * 2 + 1]); + unsigned char byte = (msn << 4) + lsn; + + dc_buffer_append (buffer, &byte, 1); + } + + return buffer; +} + void dctool_file_write (const char *filename, dc_buffer_t *buffer) { diff --git a/examples/common.h b/examples/common.h index 55dbb91..f17d578 100644 --- a/examples/common.h +++ b/examples/common.h @@ -45,6 +45,9 @@ dctool_event_cb (dc_device_t *device, dc_event_type_t event, const void *data, v dc_status_t dctool_descriptor_search (dc_descriptor_t **out, const char *name, dc_family_t family, unsigned int model); +dc_buffer_t * +dctool_convert_hex2bin (const char *str); + void dctool_file_write (const char *filename, dc_buffer_t *buffer); From 38c9ebc74e704167ca83bed8c718a626aaac622f Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 15:36:29 +0100 Subject: [PATCH 14/45] Add the help command. --- examples/Makefile.am | 1 + examples/dctool.c | 83 +++++++++++++++++++++----------- examples/dctool.h | 8 ++++ examples/dctool_help.c | 105 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 170 insertions(+), 27 deletions(-) create mode 100644 examples/dctool_help.c diff --git a/examples/Makefile.am b/examples/Makefile.am index 29f4bb6..65a4024 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -9,5 +9,6 @@ dctool_SOURCES = \ common.c \ dctool.h \ dctool.c \ + dctool_help.c \ utils.h \ utils.c diff --git a/examples/dctool.c b/examples/dctool.c index 0bc3c55..28d94c1 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -48,6 +48,7 @@ #endif static const dctool_command_t *g_commands[] = { + &dctool_help, NULL }; @@ -70,6 +71,51 @@ dctool_command_find (const char *name) return g_commands[i]; } +void +dctool_command_showhelp (const dctool_command_t *command) +{ + if (command == NULL) { + unsigned int maxlength = 0; + for (size_t i = 0; g_commands[i] != NULL; ++i) { + unsigned int length = strlen (g_commands[i]->name); + if (length > maxlength) + maxlength = length; + } + printf ( + "A simple command line interface for the libdivecomputer library\n" + "\n" + "Usage:\n" + " dctool [options] []\n" + "\n" + "Options:\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help Show help message\n" + " -d, --device Device name\n" + " -f, --family Device family type\n" + " -m, --model Device model number\n" + " -l, --logfile Logfile\n" + " -q, --quiet Quiet mode\n" + " -v, --verbose Verbose mode\n" +#else + " -h Show help message\n" + " -d Device name\n" + " -f Family type\n" + " -m Model number\n" + " -l Logfile\n" + " -q Quiet mode\n" + " -v Verbose mode\n" +#endif + "\n" + "Available commands:\n"); + for (size_t i = 0; g_commands[i] != NULL; ++i) { + printf (" %-*s%s\n", maxlength + 3, g_commands[i]->name, g_commands[i]->description); + } + printf ("\nSee 'dctool help ' for more information on a specific command.\n\n"); + } else { + printf ("%s\n\n%s\n", command->description, command->usage); + } +} + int dctool_cancel_cb (void *userdata) { @@ -165,34 +211,17 @@ main (int argc, char *argv[]) argv += optind; optind = RESET; - // Show help message. + // Translate the help option into a command. + char *argv_help[] = {(char *) "help", NULL, NULL}; if (help || argv[0] == NULL) { - printf ( - "A simple command line interface for the libdivecomputer library\n" - "\n" - "Usage:\n" - " dctool [options] []\n" - "\n" - "Options:\n" -#ifdef HAVE_GETOPT_LONG - " -h, --help Show help message\n" - " -d, --device Device name\n" - " -f, --family Device family type\n" - " -m, --model Device model number\n" - " -l, --logfile Logfile\n" - " -q, --quiet Quiet mode\n" - " -v, --verbose Verbose mode\n" -#else - " -h Show help message\n" - " -d Device name\n" - " -f Family type\n" - " -m Model number\n" - " -l Logfile\n" - " -q Quiet mode\n" - " -v Verbose mode\n" -#endif - "\n"); - return EXIT_SUCCESS; + if (argv[0]) { + argv_help[1] = argv[0]; + argv = argv_help; + argc = 2; + } else { + argv = argv_help; + argc = 1; + } } // Try to find the command. diff --git a/examples/dctool.h b/examples/dctool.h index f8a08ac..8edbc6a 100644 --- a/examples/dctool.h +++ b/examples/dctool.h @@ -42,6 +42,14 @@ typedef struct dctool_command_t { const char *usage; } dctool_command_t; +extern const dctool_command_t dctool_help; + +const dctool_command_t * +dctool_command_find (const char *name); + +void +dctool_command_showhelp (const dctool_command_t *command); + int dctool_cancel_cb (void *userdata); diff --git a/examples/dctool_help.c b/examples/dctool_help.c new file mode 100644 index 0000000..2848c24 --- /dev/null +++ b/examples/dctool_help.c @@ -0,0 +1,105 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif + +#include +#include + +#include "dctool.h" +#include "utils.h" + +static int +dctool_help_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t *descriptor) +{ + // Default option values. + unsigned int help = 0; + + // Parse the command-line options. + int opt = 0; + const char *optstring = "h"; +#ifdef HAVE_GETOPT_LONG + struct option options[] = { + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0 } + }; + while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { +#else + while ((opt = getopt (argc, argv, optstring)) != -1) { +#endif + switch (opt) { + case 'h': + help = 1; + break; + default: + return EXIT_FAILURE; + } + } + + argc -= optind; + argv += optind; + + // Show help message. + if (help) { + dctool_command_showhelp (&dctool_help); + return EXIT_SUCCESS; + } + + // Try to find the command. + const dctool_command_t *command = NULL; + if (argv[0] != NULL) { + command = dctool_command_find (argv[0]); + if (command == NULL) { + message ("Unknown command %s.\n", argv[0]); + return EXIT_FAILURE; + } + } + + // Show help message for the command. + dctool_command_showhelp (command); + + return EXIT_SUCCESS; +} + +const dctool_command_t dctool_help = { + dctool_help_run, + DCTOOL_CONFIG_NONE, + "help", + "Show basic help instructions", + "Usage:\n" + " dctool help [options] []\n" + "\n" + "Options:\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help Show help message\n" +#else + " -h Show help message\n" +#endif +}; From 4dee95d352a3767d75fc1def0b25c1ae8d72bd33 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 17:36:32 +0100 Subject: [PATCH 15/45] Add the version command. --- examples/Makefile.am | 1 + examples/dctool.c | 1 + examples/dctool.h | 1 + examples/dctool_version.c | 94 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+) create mode 100644 examples/dctool_version.c diff --git a/examples/Makefile.am b/examples/Makefile.am index 65a4024..186ec97 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -10,5 +10,6 @@ dctool_SOURCES = \ dctool.h \ dctool.c \ dctool_help.c \ + dctool_version.c \ utils.h \ utils.c diff --git a/examples/dctool.c b/examples/dctool.c index 28d94c1..da36120 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -49,6 +49,7 @@ static const dctool_command_t *g_commands[] = { &dctool_help, + &dctool_version, NULL }; diff --git a/examples/dctool.h b/examples/dctool.h index 8edbc6a..3b422bd 100644 --- a/examples/dctool.h +++ b/examples/dctool.h @@ -43,6 +43,7 @@ typedef struct dctool_command_t { } dctool_command_t; extern const dctool_command_t dctool_help; +extern const dctool_command_t dctool_version; const dctool_command_t * dctool_command_find (const char *name); diff --git a/examples/dctool_version.c b/examples/dctool_version.c new file mode 100644 index 0000000..deb0702 --- /dev/null +++ b/examples/dctool_version.c @@ -0,0 +1,94 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif + +#include +#include +#include + +#include "dctool.h" + +static int +dctool_version_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t *descriptor) +{ + // Default option values. + unsigned int help = 0; + + // Parse the command-line options. + int opt = 0; + const char *optstring = "h"; +#ifdef HAVE_GETOPT_LONG + struct option options[] = { + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0 } + }; + while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { +#else + while ((opt = getopt (argc, argv, optstring)) != -1) { +#endif + switch (opt) { + case 'h': + help = 1; + break; + default: + return EXIT_FAILURE; + } + } + + argc -= optind; + argv += optind; + + // Show help message. + if (help) { + dctool_command_showhelp (&dctool_version); + return EXIT_SUCCESS; + } + + printf ("libdivecomputer version %s\n", dc_version (NULL)); + + return EXIT_SUCCESS; +} + +const dctool_command_t dctool_version = { + dctool_version_run, + DCTOOL_CONFIG_NONE, + "version", + "Show version information", + "Usage:\n" + " dctool version [options]\n" + "\n" + "Options:\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help Show help message\n" +#else + " -h Show help message\n" +#endif +}; From ff7c3f6901655416389aaa995bbc40c4042465d6 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 19:06:34 +0100 Subject: [PATCH 16/45] Add the list command. --- examples/Makefile.am | 1 + examples/dctool.c | 1 + examples/dctool.h | 1 + examples/dctool_list.c | 103 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 examples/dctool_list.c diff --git a/examples/Makefile.am b/examples/Makefile.am index 186ec97..0356d90 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -11,5 +11,6 @@ dctool_SOURCES = \ dctool.c \ dctool_help.c \ dctool_version.c \ + dctool_list.c \ utils.h \ utils.c diff --git a/examples/dctool.c b/examples/dctool.c index da36120..7cf6728 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -50,6 +50,7 @@ static const dctool_command_t *g_commands[] = { &dctool_help, &dctool_version, + &dctool_list, NULL }; diff --git a/examples/dctool.h b/examples/dctool.h index 3b422bd..c1239a0 100644 --- a/examples/dctool.h +++ b/examples/dctool.h @@ -44,6 +44,7 @@ typedef struct dctool_command_t { extern const dctool_command_t dctool_help; extern const dctool_command_t dctool_version; +extern const dctool_command_t dctool_list; const dctool_command_t * dctool_command_find (const char *name); diff --git a/examples/dctool_list.c b/examples/dctool_list.c new file mode 100644 index 0000000..89e5386 --- /dev/null +++ b/examples/dctool_list.c @@ -0,0 +1,103 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif + +#include +#include +#include + +#include "dctool.h" + +static int +dctool_list_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t *dummy) +{ + // Default option values. + unsigned int help = 0; + + // Parse the command-line options. + int opt = 0; + const char *optstring = "h"; +#ifdef HAVE_GETOPT_LONG + struct option options[] = { + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0 } + }; + while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { +#else + while ((opt = getopt (argc, argv, optstring)) != -1) { +#endif + switch (opt) { + case 'h': + help = 1; + break; + default: + return EXIT_FAILURE; + } + } + + argc -= optind; + argv += optind; + + // Show help message. + if (help) { + dctool_command_showhelp (&dctool_list); + return EXIT_SUCCESS; + } + + dc_iterator_t *iterator = NULL; + dc_descriptor_t *descriptor = NULL; + dc_descriptor_iterator (&iterator); + while (dc_iterator_next (iterator, &descriptor) == DC_STATUS_SUCCESS) { + printf ("%s %s\n", + dc_descriptor_get_vendor (descriptor), + dc_descriptor_get_product (descriptor)); + dc_descriptor_free (descriptor); + } + dc_iterator_free (iterator); + + return EXIT_SUCCESS; +} + +const dctool_command_t dctool_list = { + dctool_list_run, + DCTOOL_CONFIG_NONE, + "list", + "List supported devices", + "Usage:\n" + " dctool list [options]\n" + "\n" + "Options:\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help Show help message\n" +#else + " -h Show help message\n" +#endif +}; From bfbb56c781f209694b51904572888132faeeef63 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 19:08:57 +0100 Subject: [PATCH 17/45] Add the dump command. --- examples/Makefile.am | 1 + examples/dctool.c | 1 + examples/dctool.h | 1 + examples/dctool_dump.c | 191 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 194 insertions(+) create mode 100644 examples/dctool_dump.c diff --git a/examples/Makefile.am b/examples/Makefile.am index 0356d90..fffc238 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -12,5 +12,6 @@ dctool_SOURCES = \ dctool_help.c \ dctool_version.c \ dctool_list.c \ + dctool_dump.c \ utils.h \ utils.c diff --git a/examples/dctool.c b/examples/dctool.c index 7cf6728..24f14c9 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -51,6 +51,7 @@ static const dctool_command_t *g_commands[] = { &dctool_help, &dctool_version, &dctool_list, + &dctool_dump, NULL }; diff --git a/examples/dctool.h b/examples/dctool.h index c1239a0..064ea9b 100644 --- a/examples/dctool.h +++ b/examples/dctool.h @@ -45,6 +45,7 @@ typedef struct dctool_command_t { extern const dctool_command_t dctool_help; extern const dctool_command_t dctool_version; extern const dctool_command_t dctool_list; +extern const dctool_command_t dctool_dump; const dctool_command_t * dctool_command_find (const char *name); diff --git a/examples/dctool_dump.c b/examples/dctool_dump.c new file mode 100644 index 0000000..ce59899 --- /dev/null +++ b/examples/dctool_dump.c @@ -0,0 +1,191 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif + +#include +#include +#include + +#include "dctool.h" +#include "common.h" +#include "utils.h" + +static dc_status_t +dump (dc_context_t *context, dc_descriptor_t *descriptor, const char *devname, dc_buffer_t *fingerprint, dc_buffer_t *buffer) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + dc_device_t *device = NULL; + + // Open the device. + message ("Opening the device (%s %s, %s).\n", + dc_descriptor_get_vendor (descriptor), + dc_descriptor_get_product (descriptor), + devname ? devname : "null"); + rc = dc_device_open (&device, context, descriptor, devname); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error opening the device."); + goto cleanup; + } + + // Register the event handler. + message ("Registering the event handler.\n"); + int events = DC_EVENT_WAITING | DC_EVENT_PROGRESS | DC_EVENT_DEVINFO | DC_EVENT_CLOCK | DC_EVENT_VENDOR; + rc = dc_device_set_events (device, events, dctool_event_cb, NULL); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the event handler."); + goto cleanup; + } + + // Register the cancellation handler. + message ("Registering the cancellation handler.\n"); + rc = dc_device_set_cancel (device, dctool_cancel_cb, NULL); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the cancellation handler."); + goto cleanup; + } + + // Register the fingerprint data. + if (fingerprint) { + message ("Registering the fingerprint data.\n"); + rc = dc_device_set_fingerprint (device, dc_buffer_get_data (fingerprint), dc_buffer_get_size (fingerprint)); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the fingerprint data."); + goto cleanup; + } + } + + // Download the memory dump. + message ("Downloading the memory dump.\n"); + rc = dc_device_dump (device, buffer); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error downloading the memory dump."); + goto cleanup; + } + +cleanup: + dc_device_close (device); + return rc; +} + +static int +dctool_dump_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t *descriptor) +{ + int exitcode = EXIT_SUCCESS; + dc_status_t status = DC_STATUS_SUCCESS; + dc_buffer_t *fingerprint = NULL; + dc_buffer_t *buffer = NULL; + + // Default option values. + unsigned int help = 0; + const char *fphex = NULL; + const char *filename = NULL; + + // Parse the command-line options. + int opt = 0; + const char *optstring = "ho:p:"; +#ifdef HAVE_GETOPT_LONG + struct option options[] = { + {"help", no_argument, 0, 'h'}, + {"output", required_argument, 0, 'o'}, + {"fingerprint", required_argument, 0, 'p'}, + {0, 0, 0, 0 } + }; + while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { +#else + while ((opt = getopt (argc, argv, optstring)) != -1) { +#endif + switch (opt) { + case 'h': + help = 1; + break; + case 'o': + filename = optarg; + break; + case 'p': + fphex = optarg; + break; + default: + return EXIT_FAILURE; + } + } + + argc -= optind; + argv += optind; + + // Show help message. + if (help) { + dctool_command_showhelp (&dctool_dump); + return EXIT_SUCCESS; + } + + // Convert the fingerprint to binary. + fingerprint = dctool_convert_hex2bin (fphex); + + // Allocate a memory buffer. + buffer = dc_buffer_new (0); + + // Download the memory dump. + status = dump (context, descriptor, argv[0], fingerprint, buffer); + if (status != DC_STATUS_SUCCESS) { + message ("ERROR: %s\n", dctool_errmsg (status)); + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Write the memory dump to disk. + dctool_file_write (filename, buffer); + +cleanup: + dc_buffer_free (buffer); + dc_buffer_free (fingerprint); + return exitcode; +} + +const dctool_command_t dctool_dump = { + dctool_dump_run, + DCTOOL_CONFIG_DESCRIPTOR, + "dump", + "Download a memory dump", + "Usage:\n" + " dctool dump [options] \n" + "\n" + "Options:\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help Show help message\n" + " -o, --output Output filename\n" + " -p, --fingerprint Fingerprint data (hexadecimal)\n" +#else + " -h Show help message\n" + " -o Output filename\n" + " -p Fingerprint data (hexadecimal)\n" +#endif +}; From 195c4c7a7e240ad820b3d9c7b1f8cd402d1c8f68 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 19:19:34 +0100 Subject: [PATCH 18/45] Add the download command. --- examples/Makefile.am | 1 + examples/dctool.c | 1 + examples/dctool.h | 1 + examples/dctool_download.c | 616 +++++++++++++++++++++++++++++++++++++ 4 files changed, 619 insertions(+) create mode 100644 examples/dctool_download.c diff --git a/examples/Makefile.am b/examples/Makefile.am index fffc238..35f41bc 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -12,6 +12,7 @@ dctool_SOURCES = \ dctool_help.c \ dctool_version.c \ dctool_list.c \ + dctool_download.c \ dctool_dump.c \ utils.h \ utils.c diff --git a/examples/dctool.c b/examples/dctool.c index 24f14c9..faba3a5 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -51,6 +51,7 @@ static const dctool_command_t *g_commands[] = { &dctool_help, &dctool_version, &dctool_list, + &dctool_download, &dctool_dump, NULL }; diff --git a/examples/dctool.h b/examples/dctool.h index 064ea9b..d4a17be 100644 --- a/examples/dctool.h +++ b/examples/dctool.h @@ -45,6 +45,7 @@ typedef struct dctool_command_t { extern const dctool_command_t dctool_help; extern const dctool_command_t dctool_version; extern const dctool_command_t dctool_list; +extern const dctool_command_t dctool_download; extern const dctool_command_t dctool_dump; const dctool_command_t * diff --git a/examples/dctool_download.c b/examples/dctool_download.c new file mode 100644 index 0000000..61c4127 --- /dev/null +++ b/examples/dctool_download.c @@ -0,0 +1,616 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif + +#include +#include +#include +#include + +#include "dctool.h" +#include "common.h" +#include "utils.h" + +typedef struct event_data_t { + const char *cachedir; + dc_event_devinfo_t devinfo; +} event_data_t; + +typedef struct dive_data_t { + FILE* ostream; + dc_device_t *device; + dc_buffer_t **fingerprint; + unsigned int number; +} dive_data_t; + +typedef struct sample_data_t { + FILE* ostream; + unsigned int nsamples; +} sample_data_t; + +static void +sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata) +{ + static const char *events[] = { + "none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter", + "violation", "bookmark", "surface", "safety stop", "gaschange", + "safety stop (voluntary)", "safety stop (mandatory)", "deepstop", + "ceiling (safety stop)", "floor", "divetime", "maxdepth", + "OLF", "PO2", "airtime", "rgbm", "heading", "tissue level warning", + "gaschange2"}; + static const char *decostop[] = { + "ndl", "safety", "deco", "deep"}; + + sample_data_t *sampledata = (sample_data_t *) userdata; + + switch (type) { + case DC_SAMPLE_TIME: + if (sampledata->nsamples++) + fprintf (sampledata->ostream, "\n"); + fprintf (sampledata->ostream, "\n"); + fprintf (sampledata->ostream, " \n", value.time / 60, value.time % 60); + break; + case DC_SAMPLE_DEPTH: + fprintf (sampledata->ostream, " %.2f\n", value.depth); + break; + case DC_SAMPLE_PRESSURE: + fprintf (sampledata->ostream, " %.2f\n", value.pressure.tank, value.pressure.value); + break; + case DC_SAMPLE_TEMPERATURE: + fprintf (sampledata->ostream, " %.2f\n", value.temperature); + break; + case DC_SAMPLE_EVENT: + if (value.event.type != SAMPLE_EVENT_GASCHANGE && value.event.type != SAMPLE_EVENT_GASCHANGE2) { + fprintf (sampledata->ostream, " %s\n", + value.event.type, value.event.time, value.event.flags, value.event.value, events[value.event.type]); + } + break; + case DC_SAMPLE_RBT: + fprintf (sampledata->ostream, " %u\n", value.rbt); + break; + case DC_SAMPLE_HEARTBEAT: + fprintf (sampledata->ostream, " %u\n", value.heartbeat); + break; + case DC_SAMPLE_BEARING: + fprintf (sampledata->ostream, " %u\n", value.bearing); + break; + case DC_SAMPLE_VENDOR: + fprintf (sampledata->ostream, " ", value.vendor.type, value.vendor.size); + for (unsigned int i = 0; i < value.vendor.size; ++i) + fprintf (sampledata->ostream, "%02X", ((unsigned char *) value.vendor.data)[i]); + fprintf (sampledata->ostream, "\n"); + break; + case DC_SAMPLE_SETPOINT: + fprintf (sampledata->ostream, " %.2f\n", value.setpoint); + break; + case DC_SAMPLE_PPO2: + fprintf (sampledata->ostream, " %.2f\n", value.ppo2); + break; + case DC_SAMPLE_CNS: + fprintf (sampledata->ostream, " %.1f\n", value.cns * 100.0); + break; + case DC_SAMPLE_DECO: + fprintf (sampledata->ostream, " %s\n", + value.deco.time, value.deco.depth, decostop[value.deco.type]); + break; + case DC_SAMPLE_GASMIX: + fprintf (sampledata->ostream, " %u\n", value.gasmix); + break; + default: + break; + } +} + +static dc_status_t +doparse (FILE *ostream, dc_device_t *device, const unsigned char data[], unsigned int size) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + dc_parser_t *parser = NULL; + + // Create the parser. + message ("Creating the parser.\n"); + rc = dc_parser_new (&parser, device); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error creating the parser."); + goto cleanup; + } + + // Register the data. + message ("Registering the data.\n"); + rc = dc_parser_set_data (parser, data, size); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the data."); + goto cleanup; + } + + // Parse the datetime. + message ("Parsing the datetime.\n"); + dc_datetime_t dt = {0}; + rc = dc_parser_get_datetime (parser, &dt); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the datetime."); + goto cleanup; + } + + fprintf (ostream, "%04i-%02i-%02i %02i:%02i:%02i\n", + dt.year, dt.month, dt.day, + dt.hour, dt.minute, dt.second); + + // Parse the divetime. + message ("Parsing the divetime.\n"); + unsigned int divetime = 0; + rc = dc_parser_get_field (parser, DC_FIELD_DIVETIME, 0, &divetime); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the divetime."); + goto cleanup; + } + + fprintf (ostream, "%02u:%02u\n", + divetime / 60, divetime % 60); + + // Parse the maxdepth. + message ("Parsing the maxdepth.\n"); + double maxdepth = 0.0; + rc = dc_parser_get_field (parser, DC_FIELD_MAXDEPTH, 0, &maxdepth); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the maxdepth."); + goto cleanup; + } + + fprintf (ostream, "%.2f\n", + maxdepth); + + // Parse the temperature. + message ("Parsing the temperature.\n"); + for (unsigned int i = 0; i < 3; ++i) { + dc_field_type_t fields[] = {DC_FIELD_TEMPERATURE_SURFACE, + DC_FIELD_TEMPERATURE_MINIMUM, + DC_FIELD_TEMPERATURE_MAXIMUM}; + const char *names[] = {"surface", "minimum", "maximum"}; + + double temperature = 0.0; + rc = dc_parser_get_field (parser, fields[i], 0, &temperature); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the temperature."); + goto cleanup; + } + + if (rc != DC_STATUS_UNSUPPORTED) { + fprintf (ostream, "%.1f\n", + names[i], temperature); + } + } + + // Parse the gas mixes. + message ("Parsing the gas mixes.\n"); + unsigned int ngases = 0; + rc = dc_parser_get_field (parser, DC_FIELD_GASMIX_COUNT, 0, &ngases); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the gas mix count."); + goto cleanup; + } + + for (unsigned int i = 0; i < ngases; ++i) { + dc_gasmix_t gasmix = {0}; + rc = dc_parser_get_field (parser, DC_FIELD_GASMIX, i, &gasmix); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the gas mix."); + goto cleanup; + } + + fprintf (ostream, + "\n" + " %.1f\n" + " %.1f\n" + " %.1f\n" + "\n", + gasmix.helium * 100.0, + gasmix.oxygen * 100.0, + gasmix.nitrogen * 100.0); + } + + // Parse the tanks. + message ("Parsing the tanks.\n"); + unsigned int ntanks = 0; + rc = dc_parser_get_field (parser, DC_FIELD_TANK_COUNT, 0, &ntanks); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the tank count."); + goto cleanup; + } + + for (unsigned int i = 0; i < ntanks; ++i) { + const char *names[] = {"none", "metric", "imperial"}; + + dc_tank_t tank = {0}; + rc = dc_parser_get_field (parser, DC_FIELD_TANK, i, &tank); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the tank."); + goto cleanup; + } + + fprintf (ostream, "\n"); + if (tank.gasmix != DC_GASMIX_UNKNOWN) { + fprintf (ostream, + " %u\n", + tank.gasmix); + } + if (tank.type != DC_TANKVOLUME_NONE) { + fprintf (ostream, + " %s\n" + " %.1f\n" + " %.2f\n", + names[tank.type], tank.volume, tank.workpressure); + } + fprintf (ostream, + " %.2f\n" + " %.2f\n" + "\n", + tank.beginpressure, tank.endpressure); + } + + // Parse the dive mode. + message ("Parsing the dive mode.\n"); + dc_divemode_t divemode = DC_DIVEMODE_OC; + rc = dc_parser_get_field (parser, DC_FIELD_DIVEMODE, 0, &divemode); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the dive mode."); + goto cleanup; + } + + if (rc != DC_STATUS_UNSUPPORTED) { + const char *names[] = {"freedive", "gauge", "oc", "cc"}; + fprintf (ostream, "%s\n", + names[divemode]); + } + + // Parse the salinity. + message ("Parsing the salinity.\n"); + dc_salinity_t salinity = {DC_WATER_FRESH, 0.0}; + rc = dc_parser_get_field (parser, DC_FIELD_SALINITY, 0, &salinity); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the salinity."); + goto cleanup; + } + + if (rc != DC_STATUS_UNSUPPORTED) { + fprintf (ostream, "%.1f\n", + salinity.type, salinity.density); + } + + // Parse the atmospheric pressure. + message ("Parsing the atmospheric pressure.\n"); + double atmospheric = 0.0; + rc = dc_parser_get_field (parser, DC_FIELD_ATMOSPHERIC, 0, &atmospheric); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the atmospheric pressure."); + goto cleanup; + } + + if (rc != DC_STATUS_UNSUPPORTED) { + fprintf (ostream, "%.5f\n", + atmospheric); + } + + // Initialize the sample data. + sample_data_t sampledata = {0}; + sampledata.nsamples = 0; + sampledata.ostream = ostream; + + // Parse the sample data. + message ("Parsing the sample data.\n"); + rc = dc_parser_samples_foreach (parser, sample_cb, &sampledata); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error parsing the sample data."); + goto cleanup; + } + + if (sampledata.nsamples) + fprintf (ostream, "\n"); + +cleanup: + dc_parser_destroy (parser); + return rc; +} + +static int +dive_cb (const unsigned char *data, unsigned int size, const unsigned char *fingerprint, unsigned int fsize, void *userdata) +{ + dive_data_t *divedata = (dive_data_t *) userdata; + + divedata->number++; + + message ("Dive: number=%u, size=%u, fingerprint=", divedata->number, size); + for (unsigned int i = 0; i < fsize; ++i) + message ("%02X", fingerprint[i]); + message ("\n"); + + // Keep a copy of the most recent fingerprint. Because dives are + // guaranteed to be downloaded in reverse order, the most recent + // dive is always the first dive. + if (divedata->number == 1) { + dc_buffer_t *fp = dc_buffer_new (fsize); + dc_buffer_append (fp, fingerprint, fsize); + *divedata->fingerprint = fp; + } + + fprintf (divedata->ostream, "\n%u\n%u\n", divedata->number, size); + for (unsigned int i = 0; i < fsize; ++i) + fprintf (divedata->ostream, "%02X", fingerprint[i]); + fprintf (divedata->ostream, "\n"); + + doparse (divedata->ostream, divedata->device, data, size); + + fprintf (divedata->ostream, "\n"); + + return 1; +} + +static void +event_cb (dc_device_t *device, dc_event_type_t event, const void *data, void *userdata) +{ + const dc_event_devinfo_t *devinfo = (const dc_event_devinfo_t *) data; + + event_data_t *eventdata = (event_data_t *) userdata; + + // Forward to the default event handler. + dctool_event_cb (device, event, data, userdata); + + switch (event) { + case DC_EVENT_DEVINFO: + // Load the fingerprint from the cache. If there is no + // fingerprint present in the cache, a NULL buffer is returned, + // and the registered fingerprint will be cleared. + if (eventdata->cachedir) { + char filename[1024] = {0}; + dc_family_t family = DC_FAMILY_NULL; + dc_buffer_t *fingerprint = NULL; + + // Generate the fingerprint filename. + family = dc_device_get_type (device); + snprintf (filename, sizeof (filename), "%s/%s-%08X.bin", + eventdata->cachedir, dctool_family_name (family), devinfo->serial); + + // Read the fingerprint file. + fingerprint = dctool_file_read (filename); + + // Register the fingerprint data. + dc_device_set_fingerprint (device, + dc_buffer_get_data (fingerprint), + dc_buffer_get_size (fingerprint)); + + // Free the buffer again. + dc_buffer_free (fingerprint); + } + + // Keep a copy of the event data. It will be used for generating + // the fingerprint filename again after a (successful) download. + eventdata->devinfo = *devinfo; + break; + default: + break; + } +} + +static dc_status_t +download (dc_context_t *context, dc_descriptor_t *descriptor, const char *devname, const char *cachedir, dc_buffer_t *fingerprint, FILE *ostream) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + dc_device_t *device = NULL; + dc_buffer_t *ofingerprint = NULL; + + // Open the device. + message ("Opening the device (%s %s, %s).\n", + dc_descriptor_get_vendor (descriptor), + dc_descriptor_get_product (descriptor), + devname ? devname : "null"); + rc = dc_device_open (&device, context, descriptor, devname); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error opening the device."); + goto cleanup; + } + + // Initialize the event data. + event_data_t eventdata = {0}; + if (fingerprint) { + eventdata.cachedir = NULL; + } else { + eventdata.cachedir = cachedir; + } + + // Register the event handler. + message ("Registering the event handler.\n"); + int events = DC_EVENT_WAITING | DC_EVENT_PROGRESS | DC_EVENT_DEVINFO | DC_EVENT_CLOCK | DC_EVENT_VENDOR; + rc = dc_device_set_events (device, events, event_cb, &eventdata); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the event handler."); + goto cleanup; + } + + // Register the cancellation handler. + message ("Registering the cancellation handler.\n"); + rc = dc_device_set_cancel (device, dctool_cancel_cb, NULL); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the cancellation handler."); + goto cleanup; + } + + // Register the fingerprint data. + if (fingerprint) { + message ("Registering the fingerprint data.\n"); + rc = dc_device_set_fingerprint (device, dc_buffer_get_data (fingerprint), dc_buffer_get_size (fingerprint)); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the fingerprint data."); + goto cleanup; + } + } + + // Initialize the dive data. + dive_data_t divedata = {0}; + divedata.device = device; + divedata.ostream = ostream; + divedata.fingerprint = &ofingerprint; + divedata.number = 0; + + fprintf (ostream, "\n"); + + // Download the dives. + message ("Downloading the dives.\n"); + rc = dc_device_foreach (device, dive_cb, &divedata); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error downloading the dives."); + goto cleanup; + } + + fprintf (ostream, "\n"); + + // Store the fingerprint data. + if (cachedir && ofingerprint) { + char filename[1024] = {0}; + dc_family_t family = DC_FAMILY_NULL; + + // Generate the fingerprint filename. + family = dc_device_get_type (device); + snprintf (filename, sizeof (filename), "%s/%s-%08X.bin", + cachedir, dctool_family_name (family), eventdata.devinfo.serial); + + // Write the fingerprint file. + dctool_file_write (filename, ofingerprint); + } + +cleanup: + dc_buffer_free (ofingerprint); + dc_device_close (device); + return rc; +} + +static int +dctool_download_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t *descriptor) +{ + int exitcode = EXIT_SUCCESS; + dc_status_t status = DC_STATUS_SUCCESS; + dc_buffer_t *fingerprint = NULL; + FILE *ostream = NULL; + + // Default option values. + unsigned int help = 0; + const char *fphex = NULL; + const char *filename = NULL; + const char *cachedir = NULL; + + // Parse the command-line options. + int opt = 0; + const char *optstring = "ho:p:c:"; +#ifdef HAVE_GETOPT_LONG + struct option options[] = { + {"help", no_argument, 0, 'h'}, + {"output", required_argument, 0, 'o'}, + {"fingerprint", required_argument, 0, 'p'}, + {"cache", required_argument, 0, 'c'}, + {0, 0, 0, 0 } + }; + while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { +#else + while ((opt = getopt (argc, argv, optstring)) != -1) { +#endif + switch (opt) { + case 'h': + help = 1; + break; + case 'o': + filename = optarg; + break; + case 'p': + fphex = optarg; + break; + case 'c': + cachedir = optarg; + break; + default: + return EXIT_FAILURE; + } + } + + argc -= optind; + argv += optind; + + // Show help message. + if (help) { + dctool_command_showhelp (&dctool_download); + return EXIT_SUCCESS; + } + + // Convert the fingerprint to binary. + fingerprint = dctool_convert_hex2bin (fphex); + + // Open the output file. + ostream = fopen (filename, "w"); + if (ostream == NULL) { + message ("Failed to open the output file.\n"); + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Download the dives. + status = download (context, descriptor, argv[0], cachedir, fingerprint, ostream); + if (status != DC_STATUS_SUCCESS) { + message ("ERROR: %s\n", dctool_errmsg (status)); + exitcode = EXIT_FAILURE; + goto cleanup; + } + +cleanup: + if (ostream) fclose (ostream); + dc_buffer_free (fingerprint); + return exitcode; +} + +const dctool_command_t dctool_download = { + dctool_download_run, + DCTOOL_CONFIG_DESCRIPTOR, + "download", + "Download the dives", + "Usage:\n" + " dctool download [options] \n" + "\n" + "Options:\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help Show help message\n" + " -o, --output Output filename\n" + " -p, --fingerprint Fingerprint data (hexadecimal)\n" + " -c, --cache Cache directory\n" +#else + " -h Show help message\n" + " -o Output filename\n" + " -p Fingerprint data (hexadecimal)\n" + " -c Cache directory\n" +#endif +}; From ce472ffa19fcdd5fbbe6f86170e4d54b518fade2 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 19:46:48 +0100 Subject: [PATCH 19/45] Add the read and write commands. --- examples/Makefile.am | 2 + examples/dctool.c | 2 + examples/dctool.h | 2 + examples/dctool_read.c | 197 +++++++++++++++++++++++++++++++++++++++ examples/dctool_write.c | 200 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 403 insertions(+) create mode 100644 examples/dctool_read.c create mode 100644 examples/dctool_write.c diff --git a/examples/Makefile.am b/examples/Makefile.am index 35f41bc..a0674ca 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -14,5 +14,7 @@ dctool_SOURCES = \ dctool_list.c \ dctool_download.c \ dctool_dump.c \ + dctool_read.c \ + dctool_write.c \ utils.h \ utils.c diff --git a/examples/dctool.c b/examples/dctool.c index faba3a5..d174372 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -53,6 +53,8 @@ static const dctool_command_t *g_commands[] = { &dctool_list, &dctool_download, &dctool_dump, + &dctool_read, + &dctool_write, NULL }; diff --git a/examples/dctool.h b/examples/dctool.h index d4a17be..a818aee 100644 --- a/examples/dctool.h +++ b/examples/dctool.h @@ -47,6 +47,8 @@ extern const dctool_command_t dctool_version; extern const dctool_command_t dctool_list; extern const dctool_command_t dctool_download; extern const dctool_command_t dctool_dump; +extern const dctool_command_t dctool_read; +extern const dctool_command_t dctool_write; const dctool_command_t * dctool_command_find (const char *name); diff --git a/examples/dctool_read.c b/examples/dctool_read.c new file mode 100644 index 0000000..85bd9de --- /dev/null +++ b/examples/dctool_read.c @@ -0,0 +1,197 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif + +#include +#include +#include + +#include "dctool.h" +#include "common.h" +#include "utils.h" + +static dc_status_t +doread (dc_context_t *context, dc_descriptor_t *descriptor, const char *devname, unsigned int address, dc_buffer_t *buffer) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + dc_device_t *device = NULL; + + // Open the device. + message ("Opening the device (%s %s, %s).\n", + dc_descriptor_get_vendor (descriptor), + dc_descriptor_get_product (descriptor), + devname ? devname : "null"); + rc = dc_device_open (&device, context, descriptor, devname); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error opening the device."); + goto cleanup; + } + + // Register the event handler. + message ("Registering the event handler.\n"); + int events = DC_EVENT_WAITING | DC_EVENT_PROGRESS | DC_EVENT_DEVINFO | DC_EVENT_CLOCK | DC_EVENT_VENDOR; + rc = dc_device_set_events (device, events, dctool_event_cb, NULL); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the event handler."); + goto cleanup; + } + + // Register the cancellation handler. + message ("Registering the cancellation handler.\n"); + rc = dc_device_set_cancel (device, dctool_cancel_cb, NULL); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the cancellation handler."); + goto cleanup; + } + + // Read data from the internal memory. + message ("Reading data from the internal memory.\n"); + rc = dc_device_read (device, address, dc_buffer_get_data (buffer), dc_buffer_get_size (buffer)); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error reading from the internal memory."); + goto cleanup; + } + +cleanup: + dc_device_close (device); + return rc; +} + +static int +dctool_read_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t *descriptor) +{ + int exitcode = EXIT_SUCCESS; + dc_status_t status = DC_STATUS_SUCCESS; + dc_buffer_t *buffer = NULL; + + // Default option values. + unsigned int help = 0; + const char *filename = NULL; + unsigned int address = 0, have_address = 0; + unsigned int count = 0, have_count = 0; + + // Parse the command-line options. + int opt = 0; + const char *optstring = "ha:c:o:"; +#ifdef HAVE_GETOPT_LONG + struct option options[] = { + {"help", no_argument, 0, 'h'}, + {"address", required_argument, 0, 'a'}, + {"count", required_argument, 0, 'c'}, + {"output", required_argument, 0, 'o'}, + {0, 0, 0, 0 } + }; + while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { +#else + while ((opt = getopt (argc, argv, optstring)) != -1) { +#endif + switch (opt) { + case 'h': + help = 1; + break; + case 'a': + address = strtoul (optarg, NULL, 0); + have_address = 1; + break; + case 'c': + count = strtoul (optarg, NULL, 0); + have_count = 1; + break; + case 'o': + filename = optarg; + break; + default: + return EXIT_FAILURE; + } + } + + argc -= optind; + argv += optind; + + // Show help message. + if (help) { + dctool_command_showhelp (&dctool_read); + return EXIT_SUCCESS; + } + + // Check mandatory arguments. + if (!have_address || !have_count) { + message ("No memory address or byte count specified.\n"); + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Allocate a memory buffer. + buffer = dc_buffer_new (count); + dc_buffer_resize (buffer, count); + if (buffer == NULL) { + message ("Failed to allocate a memory buffer.\n"); + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Read data from the internal memory. + status = doread (context, descriptor, argv[0], address, buffer); + if (status != DC_STATUS_SUCCESS) { + message ("ERROR: %s\n", dctool_errmsg (status)); + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Write the buffer to file. + dctool_file_write (filename, buffer); + +cleanup: + dc_buffer_free (buffer); + return exitcode; +} + +const dctool_command_t dctool_read = { + dctool_read_run, + DCTOOL_CONFIG_DESCRIPTOR, + "read", + "Read data from the internal memory", + "Usage:\n" + " dctool read [options] \n" + "\n" + "Options:\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help Show help message\n" + " -a, --address
Memory address\n" + " -c, --count Number of bytes\n" + " -o, --output Output filename\n" +#else + " -h Show help message\n" + " -a
Memory address\n" + " -c Number of bytes\n" + " -o Output filename\n" +#endif +}; diff --git a/examples/dctool_write.c b/examples/dctool_write.c new file mode 100644 index 0000000..4bf193b --- /dev/null +++ b/examples/dctool_write.c @@ -0,0 +1,200 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif + +#include +#include +#include + +#include "dctool.h" +#include "common.h" +#include "utils.h" + +static dc_status_t +dowrite (dc_context_t *context, dc_descriptor_t *descriptor, const char *devname, unsigned int address, dc_buffer_t *buffer) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + dc_device_t *device = NULL; + + // Open the device. + message ("Opening the device (%s %s, %s).\n", + dc_descriptor_get_vendor (descriptor), + dc_descriptor_get_product (descriptor), + devname ? devname : "null"); + rc = dc_device_open (&device, context, descriptor, devname); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error opening the device."); + goto cleanup; + } + + // Register the event handler. + message ("Registering the event handler.\n"); + int events = DC_EVENT_WAITING | DC_EVENT_PROGRESS | DC_EVENT_DEVINFO | DC_EVENT_CLOCK | DC_EVENT_VENDOR; + rc = dc_device_set_events (device, events, dctool_event_cb, NULL); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the event handler."); + goto cleanup; + } + + // Register the cancellation handler. + message ("Registering the cancellation handler.\n"); + rc = dc_device_set_cancel (device, dctool_cancel_cb, NULL); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the cancellation handler."); + goto cleanup; + } + + // Write data to the internal memory. + message ("Writing data to the internal memory.\n"); + rc = dc_device_write (device, address, dc_buffer_get_data (buffer), dc_buffer_get_size (buffer)); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error writing to the internal memory."); + goto cleanup; + } + +cleanup: + dc_device_close (device); + return rc; +} + +static int +dctool_write_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t *descriptor) +{ + int exitcode = EXIT_SUCCESS; + dc_status_t status = DC_STATUS_SUCCESS; + dc_buffer_t *buffer = NULL; + + // Default option values. + unsigned int help = 0; + const char *filename = NULL; + unsigned int address = 0, have_address = 0; + unsigned int count = 0, have_count = 0; + + // Parse the command-line options. + int opt = 0; + const char *optstring = "ha:c:i:"; +#ifdef HAVE_GETOPT_LONG + struct option options[] = { + {"help", no_argument, 0, 'h'}, + {"address", required_argument, 0, 'a'}, + {"count", required_argument, 0, 'c'}, + {"input", required_argument, 0, 'i'}, + {0, 0, 0, 0 } + }; + while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { +#else + while ((opt = getopt (argc, argv, optstring)) != -1) { +#endif + switch (opt) { + case 'h': + help = 1; + break; + case 'a': + address = strtoul (optarg, NULL, 0); + have_address = 1; + break; + case 'c': + count = strtoul (optarg, NULL, 0); + have_count = 1; + break; + case 'i': + filename = optarg; + break; + default: + return EXIT_FAILURE; + } + } + + argc -= optind; + argv += optind; + + // Show help message. + if (help) { + dctool_command_showhelp (&dctool_write); + return EXIT_SUCCESS; + } + + // Check mandatory arguments. + if (!have_address) { + message ("No memory address specified.\n"); + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Read the buffer from file. + buffer = dctool_file_read (filename); + if (buffer == NULL) { + message ("Failed to read the input file.\n"); + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Check the number of bytes (if provided) + if (have_count && count != dc_buffer_get_size (buffer)) { + message ("Number of bytes doesn't match file length.\n"); + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Write data to the internal memory. + status = dowrite (context, descriptor, argv[0], address, buffer); + if (status != DC_STATUS_SUCCESS) { + message ("ERROR: %s\n", dctool_errmsg (status)); + exitcode = EXIT_FAILURE; + goto cleanup; + } + +cleanup: + dc_buffer_free (buffer); + return exitcode; +} + +const dctool_command_t dctool_write = { + dctool_write_run, + DCTOOL_CONFIG_DESCRIPTOR, + "write", + "Write data to the internal memory", + "Usage:\n" + " dctool write [options] \n" + "\n" + "Options:\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help Show help message\n" + " -a, --address
Memory address\n" + " -c, --count Number of bytes\n" + " -i, --input Input filename\n" +#else + " -h Show help message\n" + " -a
Memory address\n" + " -c Number of bytes\n" + " -i Input filename\n" +#endif +}; From 013882f3f20c5659f46f57dbd069b0915dce6176 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 20:28:22 +0100 Subject: [PATCH 20/45] Add the fwupdate command. --- examples/Makefile.am | 1 + examples/dctool.c | 1 + examples/dctool.h | 1 + examples/dctool_fwupdate.c | 179 +++++++++++++++++++++++++++++++++++++ 4 files changed, 182 insertions(+) create mode 100644 examples/dctool_fwupdate.c diff --git a/examples/Makefile.am b/examples/Makefile.am index a0674ca..cb13b64 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -16,5 +16,6 @@ dctool_SOURCES = \ dctool_dump.c \ dctool_read.c \ dctool_write.c \ + dctool_fwupdate.c \ utils.h \ utils.c diff --git a/examples/dctool.c b/examples/dctool.c index d174372..4d70c0e 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -55,6 +55,7 @@ static const dctool_command_t *g_commands[] = { &dctool_dump, &dctool_read, &dctool_write, + &dctool_fwupdate, NULL }; diff --git a/examples/dctool.h b/examples/dctool.h index a818aee..a0e09d7 100644 --- a/examples/dctool.h +++ b/examples/dctool.h @@ -49,6 +49,7 @@ extern const dctool_command_t dctool_download; extern const dctool_command_t dctool_dump; extern const dctool_command_t dctool_read; extern const dctool_command_t dctool_write; +extern const dctool_command_t dctool_fwupdate; const dctool_command_t * dctool_command_find (const char *name); diff --git a/examples/dctool_fwupdate.c b/examples/dctool_fwupdate.c new file mode 100644 index 0000000..13b4fe3 --- /dev/null +++ b/examples/dctool_fwupdate.c @@ -0,0 +1,179 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif + +#include +#include +#include +#include +#include + +#include "dctool.h" +#include "common.h" +#include "utils.h" + +static dc_status_t +fwupdate (dc_context_t *context, dc_descriptor_t *descriptor, const char *devname, const char *hexfile) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + dc_device_t *device = NULL; + + // Open the device. + message ("Opening the device (%s %s, %s).\n", + dc_descriptor_get_vendor (descriptor), + dc_descriptor_get_product (descriptor), + devname ? devname : "null"); + rc = dc_device_open (&device, context, descriptor, devname); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error opening the device."); + goto cleanup; + } + + // Register the event handler. + message ("Registering the event handler.\n"); + int events = DC_EVENT_PROGRESS; + rc = dc_device_set_events (device, events, dctool_event_cb, NULL); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the event handler."); + goto cleanup; + } + + // Register the cancellation handler. + message ("Registering the cancellation handler.\n"); + rc = dc_device_set_cancel (device, dctool_cancel_cb, NULL); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the cancellation handler."); + goto cleanup; + } + + // Update the firmware. + message ("Updating the firmware.\n"); + switch (dc_device_get_type (device)) { + case DC_FAMILY_HW_OSTC: + rc = hw_ostc_device_fwupdate (device, hexfile); + break; + case DC_FAMILY_HW_OSTC3: + rc = hw_ostc3_device_fwupdate (device, hexfile); + break; + default: + rc = DC_STATUS_UNSUPPORTED; + break; + } + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error updating the firmware."); + goto cleanup; + } + +cleanup: + dc_device_close (device); + return rc; +} + +static int +dctool_fwupdate_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t *descriptor) +{ + int exitcode = EXIT_SUCCESS; + dc_status_t status = DC_STATUS_SUCCESS; + + // Default option values. + unsigned int help = 0; + const char *filename = NULL; + + // Parse the command-line options. + int opt = 0; + const char *optstring = "hf:"; +#ifdef HAVE_GETOPT_LONG + struct option options[] = { + {"help", no_argument, 0, 'h'}, + {"firmware", required_argument, 0, 'f'}, + {0, 0, 0, 0 } + }; + while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { +#else + while ((opt = getopt (argc, argv, optstring)) != -1) { +#endif + switch (opt) { + case 'f': + filename = optarg; + break; + case 'h': + help = 1; + break; + default: + return EXIT_FAILURE; + } + } + + argc -= optind; + argv += optind; + + // Show help message. + if (help) { + dctool_command_showhelp (&dctool_fwupdate); + return EXIT_SUCCESS; + } + + // Check mandatory arguments. + if (!filename) { + message ("No firmware file specified.\n"); + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Update the firmware. + status = fwupdate (context, descriptor, argv[0], filename); + if (status != DC_STATUS_SUCCESS) { + message ("ERROR: %s\n", dctool_errmsg (status)); + exitcode = EXIT_FAILURE; + goto cleanup; + } + +cleanup: + return exitcode; +} + +const dctool_command_t dctool_fwupdate = { + dctool_fwupdate_run, + DCTOOL_CONFIG_DESCRIPTOR, + "fwupdate", + "Update the firmware", + "Usage:\n" + " dctool fwupdate [options]\n" + "\n" + "Options:\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help Show help message\n" + " -f, --firmware Firmware filename\n" +#else + " -h Show help message\n" + " -f Firmware filename\n" +#endif +}; From 18d4d5dcc02f5fcd297f9ffaa057c2ecc386ece9 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 12 Oct 2015 19:46:00 +0200 Subject: [PATCH 21/45] Switch to goto style error handling. With the goto error handling, all cleanup code can be moved to a central location and no longer needs to be duplicated multiple times. --- src/atomics_cobalt.c | 37 +++++++++++++++++++------------- src/citizen_aqualand.c | 25 ++++++++++++++-------- src/cressi_edy.c | 35 ++++++++++++++++++------------- src/cressi_leonardo.c | 30 +++++++++++++++----------- src/diverite_nitekq.c | 32 +++++++++++++++------------- src/divesystem_idive.c | 25 ++++++++++++++-------- src/hw_frog.c | 31 +++++++++++++++------------ src/hw_ostc.c | 25 ++++++++++++++-------- src/hw_ostc3.c | 25 ++++++++++++++-------- src/irda.c | 21 ++++++++++--------- src/mares_darwin.c | 30 +++++++++++++++----------- src/mares_iconhd.c | 36 ++++++++++++++++++-------------- src/mares_nemo.c | 30 +++++++++++++++----------- src/mares_puck.c | 36 ++++++++++++++++++-------------- src/oceanic_atom2.c | 32 +++++++++++++++------------- src/oceanic_veo250.c | 40 ++++++++++++++++++----------------- src/oceanic_vtpro.c | 44 +++++++++++++++++++-------------------- src/reefnet_sensus.c | 25 ++++++++++++++-------- src/reefnet_sensuspro.c | 25 ++++++++++++++-------- src/reefnet_sensusultra.c | 25 ++++++++++++++-------- src/serial_posix.c | 17 ++++++++------- src/serial_win32.c | 13 +++++++----- src/shearwater_common.c | 14 +++++++++---- src/shearwater_petrel.c | 16 ++++++++------ src/shearwater_predator.c | 16 ++++++++------ src/suunto_d9.c | 36 ++++++++++++++++++-------------- src/suunto_eon.c | 30 +++++++++++++++----------- src/suunto_eonsteel.c | 24 +++++++++++++-------- src/suunto_solution.c | 30 +++++++++++++++----------- src/suunto_vyper.c | 30 +++++++++++++++----------- src/suunto_vyper2.c | 36 ++++++++++++++++++-------------- src/uwatec_aladin.c | 30 +++++++++++++++----------- src/uwatec_memomouse.c | 30 +++++++++++++++----------- src/uwatec_meridian.c | 25 ++++++++++++++-------- src/uwatec_smart.c | 30 +++++++++++++++----------- src/uwatec_smart_parser.c | 13 +++++++++--- src/zeagle_n2ition3.c | 25 ++++++++++++++-------- 37 files changed, 608 insertions(+), 416 deletions(-) diff --git a/src/atomics_cobalt.c b/src/atomics_cobalt.c index aec412d..b901f5b 100644 --- a/src/atomics_cobalt.c +++ b/src/atomics_cobalt.c @@ -82,12 +82,17 @@ static const dc_device_vtable_t atomics_cobalt_device_vtable = { dc_status_t atomics_cobalt_device_open (dc_device_t **out, dc_context_t *context) { +#ifdef HAVE_LIBUSB + dc_status_t status = DC_STATUS_SUCCESS; + atomics_cobalt_device_t *device = NULL; +#endif + if (out == NULL) return DC_STATUS_INVALIDARGS; #ifdef HAVE_LIBUSB // Allocate memory. - atomics_cobalt_device_t *device = (atomics_cobalt_device_t *) malloc (sizeof (atomics_cobalt_device_t)); + device = (atomics_cobalt_device_t *) malloc (sizeof (atomics_cobalt_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -105,39 +110,41 @@ atomics_cobalt_device_open (dc_device_t **out, dc_context_t *context) int rc = libusb_init (&device->context); if (rc < 0) { ERROR (context, "Failed to initialize usb support."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } device->handle = libusb_open_device_with_vid_pid (device->context, VID, PID); if (device->handle == NULL) { ERROR (context, "Failed to open the usb device."); - libusb_exit (device->context); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_usb_exit; } rc = libusb_claim_interface (device->handle, 0); if (rc < 0) { ERROR (context, "Failed to claim the usb interface."); - libusb_close (device->handle); - libusb_exit (device->context); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_usb_close; } - dc_status_t status = atomics_cobalt_device_version ((dc_device_t *) device, device->version, sizeof (device->version)); + status = atomics_cobalt_device_version ((dc_device_t *) device, device->version, sizeof (device->version)); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to identify the dive computer."); - libusb_close (device->handle); - libusb_exit (device->context); - free (device); - return status; + goto error_usb_close; } *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_usb_close: + libusb_close (device->handle); +error_usb_exit: + libusb_exit (device->context); +error_free: + free (device); + return status; #else return DC_STATUS_UNSUPPORTED; #endif diff --git a/src/citizen_aqualand.c b/src/citizen_aqualand.c index dc291b4..9a2812d 100644 --- a/src/citizen_aqualand.c +++ b/src/citizen_aqualand.c @@ -63,11 +63,14 @@ static const dc_device_vtable_t citizen_aqualand_device_vtable = { dc_status_t citizen_aqualand_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + citizen_aqualand_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - citizen_aqualand_device_t *device = (citizen_aqualand_device_t *) malloc (sizeof (citizen_aqualand_device_t)); + device = (citizen_aqualand_device_t *) malloc (sizeof (citizen_aqualand_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -84,25 +87,23 @@ citizen_aqualand_device_open (dc_device_t **out, dc_context_t *context, const ch int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (4800 8N1). rc = serial_configure (device->port, 4800, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (1000ms). if (serial_set_timeout (device->port, 1000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -112,6 +113,12 @@ citizen_aqualand_device_open (dc_device_t **out, dc_context_t *context, const ch *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/cressi_edy.c b/src/cressi_edy.c index 2a7b271..602ca0d 100644 --- a/src/cressi_edy.c +++ b/src/cressi_edy.c @@ -236,11 +236,14 @@ cressi_edy_quit (cressi_edy_device_t *device) dc_status_t cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + cressi_edy_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - cressi_edy_device_t *device = (cressi_edy_device_t *) malloc (sizeof (cressi_edy_device_t)); + device = (cressi_edy_device_t *) malloc (sizeof (cressi_edy_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -259,34 +262,31 @@ cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *na int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (1200 8N1). rc = serial_configure (device->port, 1200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (1000 ms). if (serial_set_timeout (device->port, 1000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the DTR and clear the RTS line. if (serial_set_dtr (device->port, 1) == -1 || serial_set_rts (device->port, 0) == -1) { ERROR (context, "Failed to set the DTR/RTS line."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -308,9 +308,8 @@ cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *na rc = serial_configure (device->port, 4800, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -320,6 +319,12 @@ cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *na *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/cressi_leonardo.c b/src/cressi_leonardo.c index 2d6d177..c02bea7 100644 --- a/src/cressi_leonardo.c +++ b/src/cressi_leonardo.c @@ -74,11 +74,14 @@ static const dc_device_vtable_t cressi_leonardo_device_vtable = { dc_status_t cressi_leonardo_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + cressi_leonardo_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - cressi_leonardo_device_t *device = (cressi_leonardo_device_t *) malloc (sizeof (cressi_leonardo_device_t)); + device = (cressi_leonardo_device_t *) malloc (sizeof (cressi_leonardo_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -95,34 +98,31 @@ cressi_leonardo_device_open (dc_device_t **out, dc_context_t *context, const cha int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (115200 8N1). rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (1000 ms). if (serial_set_timeout (device->port, 1000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Clear the DTR and set the RTS line. if (serial_set_dtr (device->port, 0) == -1 || serial_set_rts (device->port, 1) == -1) { ERROR (context, "Failed to set the DTR/RTS line."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } serial_sleep (device->port, 100); @@ -131,6 +131,12 @@ cressi_leonardo_device_open (dc_device_t **out, dc_context_t *context, const cha *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } static dc_status_t diff --git a/src/diverite_nitekq.c b/src/diverite_nitekq.c index 6ca5356..2a7c4b4 100644 --- a/src/diverite_nitekq.c +++ b/src/diverite_nitekq.c @@ -149,11 +149,14 @@ diverite_nitekq_handshake (diverite_nitekq_device_t *device) dc_status_t diverite_nitekq_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + diverite_nitekq_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - diverite_nitekq_device_t *device = (diverite_nitekq_device_t *) malloc (sizeof (diverite_nitekq_device_t)); + device = (diverite_nitekq_device_t *) malloc (sizeof (diverite_nitekq_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -170,25 +173,23 @@ diverite_nitekq_device_open (dc_device_t **out, dc_context_t *context, const cha int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (9600 8N1). rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (1000ms). if (serial_set_timeout (device->port, 1000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -196,18 +197,21 @@ diverite_nitekq_device_open (dc_device_t **out, dc_context_t *context, const cha serial_flush (device->port, SERIAL_QUEUE_BOTH); // Perform the handshaking. - dc_status_t status = diverite_nitekq_handshake (device); + status = diverite_nitekq_handshake (device); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to handshake."); - serial_close (device->port); - free (device); - return status; + goto error_close; } - *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/divesystem_idive.c b/src/divesystem_idive.c index 585bd58..af36cd0 100644 --- a/src/divesystem_idive.c +++ b/src/divesystem_idive.c @@ -110,11 +110,14 @@ divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, const ch dc_status_t divesystem_idive_device_open2 (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model) { + dc_status_t status = DC_STATUS_SUCCESS; + divesystem_idive_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - divesystem_idive_device_t *device = (divesystem_idive_device_t *) malloc (sizeof (divesystem_idive_device_t)); + device = (divesystem_idive_device_t *) malloc (sizeof (divesystem_idive_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -132,25 +135,23 @@ divesystem_idive_device_open2 (dc_device_t **out, dc_context_t *context, const c int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (115200 8N1). rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (1000ms). if (serial_set_timeout (device->port, 1000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -160,6 +161,12 @@ divesystem_idive_device_open2 (dc_device_t **out, dc_context_t *context, const c *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/hw_frog.c b/src/hw_frog.c index 43bc307..7c7b45a 100644 --- a/src/hw_frog.c +++ b/src/hw_frog.c @@ -202,11 +202,14 @@ hw_frog_transfer (hw_frog_device_t *device, dc_status_t hw_frog_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + hw_frog_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - hw_frog_device_t *device = (hw_frog_device_t *) malloc (sizeof (hw_frog_device_t)); + device = (hw_frog_device_t *) malloc (sizeof (hw_frog_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -223,25 +226,23 @@ hw_frog_device_open (dc_device_t **out, dc_context_t *context, const char *name) int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (115200 8N1). rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (3000ms). if (serial_set_timeout (device->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -249,17 +250,21 @@ hw_frog_device_open (dc_device_t **out, dc_context_t *context, const char *name) serial_flush (device->port, SERIAL_QUEUE_BOTH); // Send the init command. - dc_status_t status = hw_frog_transfer (device, NULL, INIT, NULL, 0, NULL, 0); + status = hw_frog_transfer (device, NULL, INIT, NULL, 0, NULL, 0); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to send the command."); - serial_close (device->port); - free (device); - return status; + goto error_close; } *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/hw_ostc.c b/src/hw_ostc.c index d994d38..d62466e 100644 --- a/src/hw_ostc.c +++ b/src/hw_ostc.c @@ -125,11 +125,14 @@ hw_ostc_send (hw_ostc_device_t *device, unsigned char cmd, unsigned int echo) dc_status_t hw_ostc_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + hw_ostc_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - hw_ostc_device_t *device = (hw_ostc_device_t *) malloc (sizeof (hw_ostc_device_t)); + device = (hw_ostc_device_t *) malloc (sizeof (hw_ostc_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -146,25 +149,23 @@ hw_ostc_device_open (dc_device_t **out, dc_context_t *context, const char *name) int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (115200 8N1). rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data. if (serial_set_timeout (device->port, 4000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -174,6 +175,12 @@ hw_ostc_device_open (dc_device_t **out, dc_context_t *context, const char *name) *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index fa0ec79..a7bc9a3 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -275,11 +275,14 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, dc_status_t hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + hw_ostc3_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - hw_ostc3_device_t *device = (hw_ostc3_device_t *) malloc (sizeof (hw_ostc3_device_t)); + device = (hw_ostc3_device_t *) malloc (sizeof (hw_ostc3_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -296,25 +299,23 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (115200 8N1). rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (3000ms). if (serial_set_timeout (device->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -326,6 +327,12 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/irda.c b/src/irda.c index b15d09f..3903b7b 100644 --- a/src/irda.c +++ b/src/irda.c @@ -92,8 +92,7 @@ irda_socket_open (irda_t **out, dc_context_t *context) WORD wVersionRequested = MAKEWORD (2, 2); if (WSAStartup (wVersionRequested, &wsaData) != 0) { SYSERROR (context, ERRNO); - free (device); - return -1; + goto error_free; } // Confirm that the winsock dll supports version 2.2. @@ -102,9 +101,7 @@ irda_socket_open (irda_t **out, dc_context_t *context) if (LOBYTE (wsaData.wVersion) != 2 || HIBYTE (wsaData.wVersion) != 2) { ERROR (context, "Incorrect winsock version."); - WSACleanup (); - free (device); - return -1; + goto error_wsacleanup; } #endif @@ -116,16 +113,20 @@ irda_socket_open (irda_t **out, dc_context_t *context) if (device->fd == -1) { #endif SYSERROR (context, ERRNO); -#ifdef _WIN32 - WSACleanup (); -#endif - free (device); - return -1; + goto error_wsacleanup; } *out = device; return 0; + +error_wsacleanup: +#ifdef _WIN32 + WSACleanup (); +error_free: +#endif + free (device); + return -1; } diff --git a/src/mares_darwin.c b/src/mares_darwin.c index 957e7d9..1113a46 100644 --- a/src/mares_darwin.c +++ b/src/mares_darwin.c @@ -96,11 +96,14 @@ static const mares_darwin_layout_t mares_darwinair_layout = { dc_status_t mares_darwin_device_open (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model) { + dc_status_t status = DC_STATUS_SUCCESS; + mares_darwin_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - mares_darwin_device_t *device = (mares_darwin_device_t *) malloc (sizeof (mares_darwin_device_t)); + device = (mares_darwin_device_t *) malloc (sizeof (mares_darwin_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -121,34 +124,31 @@ mares_darwin_device_open (dc_device_t **out, dc_context_t *context, const char * int rc = serial_open (&device->base.port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (9600 8N1). rc = serial_configure (device->base.port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->base.port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (1000 ms). if (serial_set_timeout (device->base.port, 1000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->base.port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the DTR/RTS lines. if (serial_set_dtr (device->base.port, 1) == -1 || serial_set_rts (device->base.port, 1) == -1) { ERROR (context, "Failed to set the DTR/RTS line."); - serial_close (device->base.port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -162,6 +162,12 @@ mares_darwin_device_open (dc_device_t **out, dc_context_t *context, const char * *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->base.port); +error_free: + free (device); + return status; } static dc_status_t diff --git a/src/mares_iconhd.c b/src/mares_iconhd.c index 02a13ad..af6b1de 100644 --- a/src/mares_iconhd.c +++ b/src/mares_iconhd.c @@ -214,11 +214,14 @@ mares_iconhd_transfer (mares_iconhd_device_t *device, dc_status_t mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model) { + dc_status_t status = DC_STATUS_SUCCESS; + mares_iconhd_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - mares_iconhd_device_t *device = (mares_iconhd_device_t *) malloc (sizeof (mares_iconhd_device_t)); + device = (mares_iconhd_device_t *) malloc (sizeof (mares_iconhd_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -239,25 +242,23 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char * int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (115200 8E1). rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_EVEN, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (1000 ms). if (serial_set_timeout (device->port, 1000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the DTR/RTS lines. @@ -265,9 +266,8 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char * serial_set_rts (device->port, 0) == -1) { ERROR (context, "Failed to set the DTR/RTS line."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -275,12 +275,10 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char * // Send the version command. unsigned char command[] = {0xC2, 0x67}; - dc_status_t status = mares_iconhd_transfer (device, command, sizeof (command), + status = mares_iconhd_transfer (device, command, sizeof (command), device->version, sizeof (device->version)); if (status != DC_STATUS_SUCCESS) { - serial_close (device->port); - free (device); - return status; + goto error_close; } // Autodetect the model using the version packet. @@ -314,6 +312,12 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char * *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/mares_nemo.c b/src/mares_nemo.c index e479b02..840c27e 100644 --- a/src/mares_nemo.c +++ b/src/mares_nemo.c @@ -90,11 +90,14 @@ static const mares_common_layout_t mares_nemo_apneist_layout = { dc_status_t mares_nemo_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + mares_nemo_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - mares_nemo_device_t *device = (mares_nemo_device_t *) malloc (sizeof (mares_nemo_device_t)); + device = (mares_nemo_device_t *) malloc (sizeof (mares_nemo_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -111,34 +114,31 @@ mares_nemo_device_open (dc_device_t **out, dc_context_t *context, const char *na int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (9600 8N1). rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (1000 ms). if (serial_set_timeout (device->port, 1000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the DTR/RTS lines. if (serial_set_dtr (device->port, 1) == -1 || serial_set_rts (device->port, 1) == -1) { ERROR (context, "Failed to set the DTR/RTS line."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -147,6 +147,12 @@ mares_nemo_device_open (dc_device_t **out, dc_context_t *context, const char *na *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/mares_puck.c b/src/mares_puck.c index 361a753..2b85b9f 100644 --- a/src/mares_puck.c +++ b/src/mares_puck.c @@ -88,11 +88,14 @@ static const mares_common_layout_t mares_nemowide_layout = { dc_status_t mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + mares_puck_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - mares_puck_device_t *device = (mares_puck_device_t *) malloc (sizeof (mares_puck_device_t)); + device = (mares_puck_device_t *) malloc (sizeof (mares_puck_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -109,34 +112,31 @@ mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *na int rc = serial_open (&device->base.port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (38400 8N1). rc = serial_configure (device->base.port, 38400, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->base.port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (1000 ms). if (serial_set_timeout (device->base.port, 1000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->base.port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Clear the DTR/RTS lines. if (serial_set_dtr (device->base.port, 0) == -1 || serial_set_rts (device->base.port, 0) == -1) { ERROR (context, "Failed to set the DTR/RTS line."); - serial_close (device->base.port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -144,11 +144,9 @@ mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *na // Identify the model number. unsigned char header[PACKETSIZE] = {0}; - dc_status_t status = mares_common_device_read ((dc_device_t *) device, 0, header, sizeof (header)); + status = mares_common_device_read ((dc_device_t *) device, 0, header, sizeof (header)); if (status != DC_STATUS_SUCCESS) { - serial_close (device->base.port); - free (device); - return status; + goto error_close; } // Override the base class values. @@ -171,6 +169,12 @@ mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *na *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->base.port); +error_free: + free (device); + return status; } diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 98a8273..c009ab1 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -520,13 +520,15 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char dc_status_t oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model) - { + dc_status_t status = DC_STATUS_SUCCESS; + oceanic_atom2_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - oceanic_atom2_device_t *device = (oceanic_atom2_device_t *) malloc (sizeof (oceanic_atom2_device_t)); + device = (oceanic_atom2_device_t *) malloc (sizeof (oceanic_atom2_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -546,8 +548,8 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Get the correct baudrate. @@ -560,17 +562,15 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char rc = serial_configure (device->port, baudrate, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (1000 ms). if (serial_set_timeout (device->port, 1000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Give the interface 100 ms to settle and draw power up. @@ -586,11 +586,9 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char // Switch the device from surface mode into download mode. Before sending // this command, the device needs to be in PC mode (automatically activated // by connecting the device), or already in download mode. - dc_status_t status = oceanic_atom2_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version)); + status = oceanic_atom2_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version)); if (status != DC_STATUS_SUCCESS) { - serial_close (device->port); - free (device); - return status; + goto error_close; } // Override the base class values. @@ -641,6 +639,12 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/oceanic_veo250.c b/src/oceanic_veo250.c index c7828e4..b21f6a0 100644 --- a/src/oceanic_veo250.c +++ b/src/oceanic_veo250.c @@ -221,11 +221,14 @@ oceanic_veo250_quit (oceanic_veo250_device_t *device) dc_status_t oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + oceanic_veo250_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - oceanic_veo250_device_t *device = (oceanic_veo250_device_t *) malloc (sizeof (oceanic_veo250_device_t)); + device = (oceanic_veo250_device_t *) malloc (sizeof (oceanic_veo250_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -246,34 +249,31 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (9600 8N1). rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (3000 ms). if (serial_set_timeout (device->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the DTR and RTS lines. if (serial_set_dtr (device->port, 1) == -1 || serial_set_rts (device->port, 1) == -1) { ERROR (context, "Failed to set the DTR/RTS line."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Give the interface 100 ms to settle and draw power up. @@ -283,11 +283,9 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char serial_flush (device->port, SERIAL_QUEUE_BOTH); // Initialize the data cable (PPS mode). - dc_status_t status = oceanic_veo250_init (device); + status = oceanic_veo250_init (device); if (status != DC_STATUS_SUCCESS) { - serial_close (device->port); - free (device); - return status; + goto error_close; } // Delay the sending of the version command. @@ -298,14 +296,18 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char // the user), or already in download mode. status = oceanic_veo250_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version)); if (status != DC_STATUS_SUCCESS) { - serial_close (device->port); - free (device); - return status; + goto error_close; } *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/oceanic_vtpro.c b/src/oceanic_vtpro.c index 5696045..92faf7a 100644 --- a/src/oceanic_vtpro.c +++ b/src/oceanic_vtpro.c @@ -254,11 +254,14 @@ oceanic_vtpro_calibrate (oceanic_vtpro_device_t *device) dc_status_t oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + oceanic_vtpro_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) malloc (sizeof (oceanic_vtpro_device_t)); + device = (oceanic_vtpro_device_t *) malloc (sizeof (oceanic_vtpro_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -277,34 +280,31 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (9600 8N1). rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (3000 ms). if (serial_set_timeout (device->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the DTR and RTS lines. if (serial_set_dtr (device->port, 1) == -1 || serial_set_rts (device->port, 1) == -1) { ERROR (context, "Failed to set the DTR/RTS line."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Give the interface 100 ms to settle and draw power up. @@ -314,11 +314,9 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char serial_flush (device->port, SERIAL_QUEUE_BOTH); // Initialize the data cable (MOD mode). - dc_status_t status = oceanic_vtpro_init (device); + status = oceanic_vtpro_init (device); if (status != DC_STATUS_SUCCESS) { - serial_close (device->port); - free (device); - return status; + goto error_close; } // Switch the device from surface mode into download mode. Before sending @@ -326,9 +324,7 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char // the user), or already in download mode. status = oceanic_vtpro_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version)); if (status != DC_STATUS_SUCCESS) { - serial_close (device->port); - free (device); - return status; + goto error_close; } // Calibrate the device. Although calibration is optional, it's highly @@ -336,9 +332,7 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char // when processing the command itself is quite slow. status = oceanic_vtpro_calibrate (device); if (status != DC_STATUS_SUCCESS) { - serial_close (device->port); - free (device); - return status; + goto error_close; } // Override the base class values. @@ -351,6 +345,12 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/reefnet_sensus.c b/src/reefnet_sensus.c index 6504342..ec0ee07 100644 --- a/src/reefnet_sensus.c +++ b/src/reefnet_sensus.c @@ -89,11 +89,14 @@ reefnet_sensus_cancel (reefnet_sensus_device_t *device) dc_status_t reefnet_sensus_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + reefnet_sensus_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - reefnet_sensus_device_t *device = (reefnet_sensus_device_t *) malloc (sizeof (reefnet_sensus_device_t)); + device = (reefnet_sensus_device_t *) malloc (sizeof (reefnet_sensus_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -114,25 +117,23 @@ reefnet_sensus_device_open (dc_device_t **out, dc_context_t *context, const char int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (19200 8N1). rc = serial_configure (device->port, 19200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (3000 ms). if (serial_set_timeout (device->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -141,6 +142,12 @@ reefnet_sensus_device_open (dc_device_t **out, dc_context_t *context, const char *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/reefnet_sensuspro.c b/src/reefnet_sensuspro.c index b462f55..d20f432 100644 --- a/src/reefnet_sensuspro.c +++ b/src/reefnet_sensuspro.c @@ -68,11 +68,14 @@ static const dc_device_vtable_t reefnet_sensuspro_device_vtable = { dc_status_t reefnet_sensuspro_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + reefnet_sensuspro_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - reefnet_sensuspro_device_t *device = (reefnet_sensuspro_device_t *) malloc (sizeof (reefnet_sensuspro_device_t)); + device = (reefnet_sensuspro_device_t *) malloc (sizeof (reefnet_sensuspro_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -92,25 +95,23 @@ reefnet_sensuspro_device_open (dc_device_t **out, dc_context_t *context, const c int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (19200 8N1). rc = serial_configure (device->port, 19200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (3000ms). if (serial_set_timeout (device->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -119,6 +120,12 @@ reefnet_sensuspro_device_open (dc_device_t **out, dc_context_t *context, const c *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/reefnet_sensusultra.c b/src/reefnet_sensusultra.c index 6405830..f16c535 100644 --- a/src/reefnet_sensusultra.c +++ b/src/reefnet_sensusultra.c @@ -77,11 +77,14 @@ static const dc_device_vtable_t reefnet_sensusultra_device_vtable = { dc_status_t reefnet_sensusultra_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + reefnet_sensusultra_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - reefnet_sensusultra_device_t *device = (reefnet_sensusultra_device_t *) malloc (sizeof (reefnet_sensusultra_device_t)); + device = (reefnet_sensusultra_device_t *) malloc (sizeof (reefnet_sensusultra_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -101,25 +104,23 @@ reefnet_sensusultra_device_open (dc_device_t **out, dc_context_t *context, const int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (115200 8N1). rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (3000ms). if (serial_set_timeout (device->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -128,6 +129,12 @@ reefnet_sensusultra_device_open (dc_device_t **out, dc_context_t *context, const *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/serial_posix.c b/src/serial_posix.c index af4beba..ee9312f 100644 --- a/src/serial_posix.c +++ b/src/serial_posix.c @@ -157,17 +157,14 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) device->fd = open (name, O_RDWR | O_NOCTTY | O_NONBLOCK); if (device->fd == -1) { SYSERROR (context, errno); - free (device); - return -1; // Error during open call. + goto error_free; } #ifndef ENABLE_PTY // Enable exclusive access mode. if (ioctl (device->fd, TIOCEXCL, NULL) != 0) { SYSERROR (context, errno); - close (device->fd); - free (device); - return -1; + goto error_close; } #endif @@ -177,14 +174,18 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) // file descriptor represents a terminal device. if (tcgetattr (device->fd, &device->tty) != 0) { SYSERROR (context, errno); - close (device->fd); - free (device); - return -1; + goto error_close; } *out = device; return 0; + +error_close: + close (device->fd); +error_free: + free (device); + return -1; } // diff --git a/src/serial_win32.c b/src/serial_win32.c index 9d5572c..00aeb4d 100644 --- a/src/serial_win32.c +++ b/src/serial_win32.c @@ -150,8 +150,7 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) NULL); if (device->hFile == INVALID_HANDLE_VALUE) { SYSERROR (context, GetLastError ()); - free (device); - return -1; + goto error_free; } // Retrieve the current communication settings and timeouts, @@ -161,14 +160,18 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) if (!GetCommState (device->hFile, &device->dcb) || !GetCommTimeouts (device->hFile, &device->timeouts)) { SYSERROR (context, GetLastError ()); - CloseHandle (device->hFile); - free (device); - return -1; + goto error_close; } *out = device; return 0; + +error_close: + CloseHandle (device->hFile); +error_free: + free (device); + return -1; } // diff --git a/src/shearwater_common.c b/src/shearwater_common.c index eabed11..ac53a7e 100644 --- a/src/shearwater_common.c +++ b/src/shearwater_common.c @@ -40,6 +40,8 @@ dc_status_t shearwater_common_open (shearwater_common_device_t *device, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + // Open the device. int rc = serial_open (&device->port, context, name); if (rc == -1) { @@ -51,15 +53,15 @@ shearwater_common_open (shearwater_common_device_t *device, dc_context_t *contex rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (3000ms). if (serial_set_timeout (device->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -67,6 +69,10 @@ shearwater_common_open (shearwater_common_device_t *device, dc_context_t *contex serial_flush (device->port, SERIAL_QUEUE_BOTH); return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); + return status; } diff --git a/src/shearwater_petrel.c b/src/shearwater_petrel.c index 3534a26..1bf98f5 100644 --- a/src/shearwater_petrel.c +++ b/src/shearwater_petrel.c @@ -79,13 +79,14 @@ str2num (unsigned char data[], unsigned int size, unsigned int offset) dc_status_t shearwater_petrel_device_open (dc_device_t **out, dc_context_t *context, const char *name) { - dc_status_t rc = DC_STATUS_SUCCESS; + dc_status_t status = DC_STATUS_SUCCESS; + shearwater_petrel_device_t *device = NULL; if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - shearwater_petrel_device_t *device = (shearwater_petrel_device_t *) malloc (sizeof (shearwater_petrel_device_t)); + device = (shearwater_petrel_device_t *) malloc (sizeof (shearwater_petrel_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -98,15 +99,18 @@ shearwater_petrel_device_open (dc_device_t **out, dc_context_t *context, const c memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - rc = shearwater_common_open (&device->base, context, name); - if (rc != DC_STATUS_SUCCESS) { - free (device); - return rc; + status = shearwater_common_open (&device->base, context, name); + if (status != DC_STATUS_SUCCESS) { + goto error_free; } *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; + +error_free: + free (device); + return status; } diff --git a/src/shearwater_predator.c b/src/shearwater_predator.c index e8a44ac..7fa6f83 100644 --- a/src/shearwater_predator.c +++ b/src/shearwater_predator.c @@ -65,13 +65,14 @@ static const dc_device_vtable_t shearwater_predator_device_vtable = { dc_status_t shearwater_predator_device_open (dc_device_t **out, dc_context_t *context, const char *name) { - dc_status_t rc = DC_STATUS_SUCCESS; + dc_status_t status = DC_STATUS_SUCCESS; + shearwater_predator_device_t *device = NULL; if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - shearwater_predator_device_t *device = (shearwater_predator_device_t *) malloc (sizeof (shearwater_predator_device_t)); + device = (shearwater_predator_device_t *) malloc (sizeof (shearwater_predator_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -84,15 +85,18 @@ shearwater_predator_device_open (dc_device_t **out, dc_context_t *context, const memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - rc = shearwater_common_open (&device->base, context, name); - if (rc != DC_STATUS_SUCCESS) { - free (device); - return rc; + status = shearwater_common_open (&device->base, context, name); + if (status != DC_STATUS_SUCCESS) { + goto error_free; } *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; + +error_free: + free (device); + return status; } diff --git a/src/suunto_d9.c b/src/suunto_d9.c index fa4a263..c0903bb 100644 --- a/src/suunto_d9.c +++ b/src/suunto_d9.c @@ -129,11 +129,14 @@ suunto_d9_device_autodetect (suunto_d9_device_t *device, unsigned int model) dc_status_t suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model) { + dc_status_t status = DC_STATUS_SUCCESS; + suunto_d9_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - suunto_d9_device_t *device = (suunto_d9_device_t *) malloc (sizeof (suunto_d9_device_t)); + device = (suunto_d9_device_t *) malloc (sizeof (suunto_d9_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -149,33 +152,30 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (9600 8N1). rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (3000 ms). if (serial_set_timeout (device->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the DTR line (power supply for the interface). if (serial_set_dtr (device->port, 1) == -1) { ERROR (context, "Failed to set the DTR line."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Give the interface 100 ms to settle and draw power up. @@ -185,12 +185,10 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam serial_flush (device->port, SERIAL_QUEUE_BOTH); // Try to autodetect the protocol variant. - dc_status_t status = suunto_d9_device_autodetect (device, model); + status = suunto_d9_device_autodetect (device, model); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to identify the protocol variant."); - serial_close (device->port); - free (device); - return status; + goto error_close; } // Override the base class values. @@ -205,6 +203,12 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/suunto_eon.c b/src/suunto_eon.c index c9c78d2..e71e315 100644 --- a/src/suunto_eon.c +++ b/src/suunto_eon.c @@ -71,11 +71,14 @@ static const suunto_common_layout_t suunto_eon_layout = { dc_status_t suunto_eon_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + suunto_eon_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - suunto_eon_device_t *device = (suunto_eon_device_t *) malloc (sizeof (suunto_eon_device_t)); + device = (suunto_eon_device_t *) malloc (sizeof (suunto_eon_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -91,38 +94,41 @@ suunto_eon_device_open (dc_device_t **out, dc_context_t *context, const char *na int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (1200 8N2). rc = serial_configure (device->port, 1200, 8, SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (1000ms). if (serial_set_timeout (device->port, 1000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Clear the RTS line. if (serial_set_rts (device->port, 0)) { ERROR (context, "Failed to set the DTR/RTS line."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/suunto_eonsteel.c b/src/suunto_eonsteel.c index feb01a3..8bd0350 100644 --- a/src/suunto_eonsteel.c +++ b/src/suunto_eonsteel.c @@ -556,6 +556,7 @@ static int initialize_eonsteel(suunto_eonsteel_device_t *eon) dc_status_t suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, const char *name, unsigned int model) { + dc_status_t status = DC_STATUS_SUCCESS; suunto_eonsteel_device_t *eon; if (out == NULL) @@ -574,16 +575,15 @@ suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, const char if (libusb_init(&eon->ctx)) { ERROR(context, "libusb_init() failed"); - free(eon); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } eon->handle = libusb_open_device_with_vid_pid(eon->ctx, 0x1493, 0x0030); if (!eon->handle) { ERROR(context, "unable to open device"); - libusb_exit(eon->ctx); - free(eon); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_usb_exit; } #if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000102) @@ -594,15 +594,21 @@ suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, const char if (initialize_eonsteel(eon) < 0) { ERROR(context, "unable to initialize device"); - libusb_close(eon->handle); - libusb_exit(eon->ctx); - free(eon); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_usb_close; } *out = (dc_device_t *) eon; return DC_STATUS_SUCCESS; + +error_usb_close: + libusb_close(eon->handle); +error_usb_exit: + libusb_exit(eon->ctx); +error_free: + free(eon); + return status; } static int count_dir_entries(struct directory_entry *de) diff --git a/src/suunto_solution.c b/src/suunto_solution.c index 1d7b227..421a090 100644 --- a/src/suunto_solution.c +++ b/src/suunto_solution.c @@ -65,11 +65,14 @@ static const dc_device_vtable_t suunto_solution_device_vtable = { dc_status_t suunto_solution_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + suunto_solution_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - suunto_solution_device_t *device = (suunto_solution_device_t *) malloc (sizeof (suunto_solution_device_t)); + device = (suunto_solution_device_t *) malloc (sizeof (suunto_solution_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -85,38 +88,41 @@ suunto_solution_device_open (dc_device_t **out, dc_context_t *context, const cha int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (1200 8N2). rc = serial_configure (device->port, 1200, 8, SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (1000ms). if (serial_set_timeout (device->port, 1000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Clear the RTS line. if (serial_set_rts (device->port, 0)) { ERROR (context, "Failed to set the DTR/RTS line."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/suunto_vyper.c b/src/suunto_vyper.c index b259259..03fbc4a 100644 --- a/src/suunto_vyper.c +++ b/src/suunto_vyper.c @@ -91,11 +91,14 @@ static const suunto_common_layout_t suunto_spyder_layout = { dc_status_t suunto_vyper_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + suunto_vyper_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - suunto_vyper_device_t *device = (suunto_vyper_device_t *) malloc (sizeof (suunto_vyper_device_t)); + device = (suunto_vyper_device_t *) malloc (sizeof (suunto_vyper_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -111,33 +114,30 @@ suunto_vyper_device_open (dc_device_t **out, dc_context_t *context, const char * int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status= DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (2400 8O1). rc = serial_configure (device->port, 2400, 8, SERIAL_PARITY_ODD, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (1000 ms). if (serial_set_timeout (device->port, 1000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the DTR line (power supply for the interface). if (serial_set_dtr (device->port, 1) == -1) { ERROR (context, "Failed to set the DTR line."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Give the interface 100 ms to settle and draw power up. @@ -149,6 +149,12 @@ suunto_vyper_device_open (dc_device_t **out, dc_context_t *context, const char * *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/suunto_vyper2.c b/src/suunto_vyper2.c index e6dbd27..efba846 100644 --- a/src/suunto_vyper2.c +++ b/src/suunto_vyper2.c @@ -80,11 +80,14 @@ static const suunto_common2_layout_t suunto_helo2_layout = { dc_status_t suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + suunto_vyper2_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - suunto_vyper2_device_t *device = (suunto_vyper2_device_t *) malloc (sizeof (suunto_vyper2_device_t)); + device = (suunto_vyper2_device_t *) malloc (sizeof (suunto_vyper2_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -100,33 +103,30 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (9600 8N1). rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (3000 ms). if (serial_set_timeout (device->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the DTR line (power supply for the interface). if (serial_set_dtr (device->port, 1) == -1) { ERROR (context, "Failed to set the DTR line."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Give the interface 100 ms to settle and draw power up. @@ -139,12 +139,10 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char serial_set_halfduplex (device->port, 1); // Read the version info. - dc_status_t status = suunto_common2_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version)); + status = suunto_common2_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version)); if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to read the version info."); - serial_close (device->port); - free (device); - return status; + goto error_close; } // Override the base class values. @@ -157,6 +155,12 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/uwatec_aladin.c b/src/uwatec_aladin.c index d01a92a..796e867 100644 --- a/src/uwatec_aladin.c +++ b/src/uwatec_aladin.c @@ -74,11 +74,14 @@ static const dc_device_vtable_t uwatec_aladin_device_vtable = { dc_status_t uwatec_aladin_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + uwatec_aladin_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - uwatec_aladin_device_t *device = (uwatec_aladin_device_t *) malloc (sizeof (uwatec_aladin_device_t)); + device = (uwatec_aladin_device_t *) malloc (sizeof (uwatec_aladin_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -97,39 +100,42 @@ uwatec_aladin_device_open (dc_device_t **out, dc_context_t *context, const char int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (19200 8N1). rc = serial_configure (device->port, 19200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (INFINITE). if (serial_set_timeout (device->port, -1) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Clear the RTS line and set the DTR line. if (serial_set_dtr (device->port, 1) == -1 || serial_set_rts (device->port, 0) == -1) { ERROR (context, "Failed to set the DTR/RTS line."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/uwatec_memomouse.c b/src/uwatec_memomouse.c index 101ff19..9608cb5 100644 --- a/src/uwatec_memomouse.c +++ b/src/uwatec_memomouse.c @@ -70,11 +70,14 @@ static const dc_device_vtable_t uwatec_memomouse_device_vtable = { dc_status_t uwatec_memomouse_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + uwatec_memomouse_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - uwatec_memomouse_device_t *device = (uwatec_memomouse_device_t *) malloc (sizeof (uwatec_memomouse_device_t)); + device = (uwatec_memomouse_device_t *) malloc (sizeof (uwatec_memomouse_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -93,34 +96,31 @@ uwatec_memomouse_device_open (dc_device_t **out, dc_context_t *context, const ch int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (9600 8N1). rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (1000 ms). if (serial_set_timeout (device->port, 1000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Clear the RTS and DTR lines. if (serial_set_rts (device->port, 0) == -1 || serial_set_dtr (device->port, 0) == -1) { ERROR (context, "Failed to set the DTR/RTS line."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -129,6 +129,12 @@ uwatec_memomouse_device_open (dc_device_t **out, dc_context_t *context, const ch *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/uwatec_meridian.c b/src/uwatec_meridian.c index fbf26c7..4828a32 100644 --- a/src/uwatec_meridian.c +++ b/src/uwatec_meridian.c @@ -186,11 +186,14 @@ uwatec_meridian_handshake (uwatec_meridian_device_t *device) dc_status_t uwatec_meridian_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + uwatec_meridian_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - uwatec_meridian_device_t *device = (uwatec_meridian_device_t *) malloc (sizeof (uwatec_meridian_device_t)); + device = (uwatec_meridian_device_t *) malloc (sizeof (uwatec_meridian_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -209,25 +212,23 @@ uwatec_meridian_device_open (dc_device_t **out, dc_context_t *context, const cha int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (57600 8N1). rc = serial_configure (device->port, 57600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (3000ms). if (serial_set_timeout (device->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -239,6 +240,12 @@ uwatec_meridian_device_open (dc_device_t **out, dc_context_t *context, const cha *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } diff --git a/src/uwatec_smart.c b/src/uwatec_smart.c index 124ffca..2b327ba 100644 --- a/src/uwatec_smart.c +++ b/src/uwatec_smart.c @@ -145,11 +145,14 @@ uwatec_smart_handshake (uwatec_smart_device_t *device) dc_status_t uwatec_smart_device_open (dc_device_t **out, dc_context_t *context) { + dc_status_t status = DC_STATUS_SUCCESS; + uwatec_smart_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - uwatec_smart_device_t *device = (uwatec_smart_device_t *) malloc (sizeof (uwatec_smart_device_t)); + device = (uwatec_smart_device_t *) malloc (sizeof (uwatec_smart_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -169,33 +172,30 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context) int rc = irda_socket_open (&device->socket, context); if (rc == -1) { ERROR (context, "Failed to open the irda socket."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Discover the device. rc = irda_socket_discover (device->socket, uwatec_smart_discovery, device); if (rc == -1) { ERROR (context, "Failed to discover the device."); - irda_socket_close (device->socket); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } if (device->address == 0) { ERROR (context, "No dive computer found."); - irda_socket_close (device->socket); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Connect the device. rc = irda_socket_connect_lsap (device->socket, device->address, 1); if (rc == -1) { ERROR (context, "Failed to connect the device."); - irda_socket_close (device->socket); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Perform the handshaking. @@ -204,6 +204,12 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context) *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; + +error_close: + irda_socket_close (device->socket); +error_free: + free (device); + return status; } diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index 9009fbe..c06e5e2 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -512,11 +512,14 @@ uwatec_smart_parser_cache (uwatec_smart_parser_t *parser) dc_status_t uwatec_smart_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model, unsigned int devtime, dc_ticks_t systime) { + dc_status_t status = DC_STATUS_SUCCESS; + uwatec_smart_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - uwatec_smart_parser_t *parser = (uwatec_smart_parser_t *) malloc (sizeof (uwatec_smart_parser_t)); + parser = (uwatec_smart_parser_t *) malloc (sizeof (uwatec_smart_parser_t)); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -594,8 +597,8 @@ uwatec_smart_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i parser->nevents[0] = C_ARRAY_SIZE (uwatec_smart_tec_events_0); break; default: - free (parser); - return DC_STATUS_INVALIDARGS; + status = DC_STATUS_INVALIDARGS; + goto error_free; } parser->cached = 0; @@ -616,6 +619,10 @@ uwatec_smart_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i *out = (dc_parser_t*) parser; return DC_STATUS_SUCCESS; + +error_free: + free (parser); + return status; } diff --git a/src/zeagle_n2ition3.c b/src/zeagle_n2ition3.c index 1c1dcf1..a98825a 100644 --- a/src/zeagle_n2ition3.c +++ b/src/zeagle_n2ition3.c @@ -137,11 +137,14 @@ zeagle_n2ition3_init (zeagle_n2ition3_device_t *device) dc_status_t zeagle_n2ition3_device_open (dc_device_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + zeagle_n2ition3_device_t *device = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - zeagle_n2ition3_device_t *device = (zeagle_n2ition3_device_t *) malloc (sizeof (zeagle_n2ition3_device_t)); + device = (zeagle_n2ition3_device_t *) malloc (sizeof (zeagle_n2ition3_device_t)); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -158,25 +161,23 @@ zeagle_n2ition3_device_open (dc_device_t **out, dc_context_t *context, const cha int rc = serial_open (&device->port, context, name); if (rc == -1) { ERROR (context, "Failed to open the serial port."); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (4800 8N1). rc = serial_configure (device->port, 4800, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (1000 ms). if (serial_set_timeout (device->port, 1000) == -1) { ERROR (context, "Failed to set the timeout."); - serial_close (device->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -188,6 +189,12 @@ zeagle_n2ition3_device_open (dc_device_t **out, dc_context_t *context, const cha *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->port); +error_free: + free (device); + return status; } From f1c024905359cc6d6d24f79f40b65d519d96b126 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 12 Oct 2015 19:51:52 +0200 Subject: [PATCH 22/45] Simplify the error handling in the close function. When the close function returns, all resources should be freed, regardless of whether an error has occured or not. The error code is purely informative. However, in order to return the first error code, which is usually the most interesting one, the current implementation is unnecessary complicated. If an error occurs, there is no need to exit immediately. Simply store the error code unless there is already a previous one, and then continue. --- msvc/libdivecomputer.vcproj | 8 ++++++++ src/Makefile.am | 1 + src/citizen_aqualand.c | 6 +++--- src/common-private.h | 37 +++++++++++++++++++++++++++++++++++++ src/common.c | 34 ++++++++++++++++++++++++++++++++++ src/cressi_edy.c | 6 +++--- src/cressi_leonardo.c | 6 +++--- src/device-private.h | 2 ++ src/diverite_nitekq.c | 6 +++--- src/divesystem_idive.c | 6 +++--- src/hw_frog.c | 15 +++++++-------- src/hw_ostc.c | 6 +++--- src/hw_ostc3.c | 10 ++++------ src/irda.c | 13 +++++-------- src/mares_darwin.c | 6 +++--- src/mares_iconhd.c | 6 +++--- src/mares_nemo.c | 6 +++--- src/mares_puck.c | 6 +++--- src/oceanic_atom2.c | 6 +++--- src/oceanic_veo250.c | 6 +++--- src/oceanic_vtpro.c | 6 +++--- src/reefnet_sensus.c | 6 +++--- src/reefnet_sensuspro.c | 6 +++--- src/reefnet_sensusultra.c | 6 +++--- src/serial_posix.c | 11 +++++------ src/serial_win32.c | 11 +++++------ src/suunto_d9.c | 6 +++--- src/suunto_eon.c | 6 +++--- src/suunto_solution.c | 6 +++--- src/suunto_vyper.c | 6 +++--- src/suunto_vyper2.c | 6 +++--- src/uwatec_aladin.c | 6 +++--- src/uwatec_memomouse.c | 6 +++--- src/uwatec_meridian.c | 6 +++--- src/uwatec_smart.c | 6 +++--- src/zeagle_n2ition3.c | 6 +++--- 36 files changed, 186 insertions(+), 112 deletions(-) create mode 100644 src/common-private.h create mode 100644 src/common.c diff --git a/msvc/libdivecomputer.vcproj b/msvc/libdivecomputer.vcproj index aff2bd7..3da8750 100644 --- a/msvc/libdivecomputer.vcproj +++ b/msvc/libdivecomputer.vcproj @@ -210,6 +210,10 @@ RelativePath="..\src\citizen_aqualand_parser.c" > + + @@ -520,6 +524,10 @@ RelativePath="..\include\libdivecomputer\citizen_aqualand.h" > + + diff --git a/src/Makefile.am b/src/Makefile.am index 64c3649..c029a79 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,6 +17,7 @@ libdivecomputer_la_SOURCES = \ version.c \ descriptor.c \ iterator-private.h iterator.c \ + common-private.h common.c \ context-private.h context.c \ device-private.h device.c \ parser-private.h parser.c \ diff --git a/src/citizen_aqualand.c b/src/citizen_aqualand.c index 9a2812d..cda3dbc 100644 --- a/src/citizen_aqualand.c +++ b/src/citizen_aqualand.c @@ -125,18 +125,18 @@ error_free: static dc_status_t citizen_aqualand_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; citizen_aqualand_device_t *device = (citizen_aqualand_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/common-private.h b/src/common-private.h new file mode 100644 index 0000000..94cfd91 --- /dev/null +++ b/src/common-private.h @@ -0,0 +1,37 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef COMMON_PRIVATE_H +#define COMMON_PRIVATE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void +dc_status_set_error (dc_status_t *status, dc_status_t error); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* COMMON_PRIVATE_H */ diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..d1141d5 --- /dev/null +++ b/src/common.c @@ -0,0 +1,34 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include + +#include "common-private.h" + +void +dc_status_set_error (dc_status_t *status, dc_status_t error) +{ + assert (status != NULL); + + if (*status == DC_STATUS_SUCCESS) + *status = error; +} diff --git a/src/cressi_edy.c b/src/cressi_edy.c index 602ca0d..e58619b 100644 --- a/src/cressi_edy.c +++ b/src/cressi_edy.c @@ -331,6 +331,7 @@ error_free: static dc_status_t cressi_edy_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; cressi_edy_device_t *device = (cressi_edy_device_t*) abstract; // Send the quit command. @@ -338,14 +339,13 @@ cressi_edy_device_close (dc_device_t *abstract) // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/cressi_leonardo.c b/src/cressi_leonardo.c index c02bea7..6ca321d 100644 --- a/src/cressi_leonardo.c +++ b/src/cressi_leonardo.c @@ -142,18 +142,18 @@ error_free: static dc_status_t cressi_leonardo_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; cressi_leonardo_device_t *device = (cressi_leonardo_device_t *) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } static dc_status_t diff --git a/src/device-private.h b/src/device-private.h index 8e183fb..9254c6c 100644 --- a/src/device-private.h +++ b/src/device-private.h @@ -27,6 +27,8 @@ #include #include +#include "common-private.h" + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ diff --git a/src/diverite_nitekq.c b/src/diverite_nitekq.c index 2a7c4b4..1d8b96a 100644 --- a/src/diverite_nitekq.c +++ b/src/diverite_nitekq.c @@ -218,6 +218,7 @@ error_free: static dc_status_t diverite_nitekq_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; diverite_nitekq_device_t *device = (diverite_nitekq_device_t*) abstract; // Disconnect. @@ -225,14 +226,13 @@ diverite_nitekq_device_close (dc_device_t *abstract) // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/divesystem_idive.c b/src/divesystem_idive.c index af36cd0..e4eec6a 100644 --- a/src/divesystem_idive.c +++ b/src/divesystem_idive.c @@ -173,18 +173,18 @@ error_free: static dc_status_t divesystem_idive_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; divesystem_idive_device_t *device = (divesystem_idive_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/hw_frog.c b/src/hw_frog.c index 7c7b45a..48c9175 100644 --- a/src/hw_frog.c +++ b/src/hw_frog.c @@ -271,27 +271,26 @@ error_free: static dc_status_t hw_frog_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; hw_frog_device_t *device = (hw_frog_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Send the exit command. - dc_status_t status = hw_frog_transfer (device, NULL, EXIT, NULL, 0, NULL, 0); - if (status != DC_STATUS_SUCCESS) { + rc = hw_frog_transfer (device, NULL, EXIT, NULL, 0, NULL, 0); + if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - serial_close (device->port); - free (device); - return status; + dc_status_set_error(&status, rc); } // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/hw_ostc.c b/src/hw_ostc.c index d62466e..42dc778 100644 --- a/src/hw_ostc.c +++ b/src/hw_ostc.c @@ -187,18 +187,18 @@ error_free: static dc_status_t hw_ostc_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; hw_ostc_device_t *device = (hw_ostc_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index a7bc9a3..20cbe8d 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -430,6 +430,7 @@ hw_ostc3_device_init (hw_ostc3_device_t *device, hw_ostc3_state_t state) static dc_status_t hw_ostc3_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; hw_ostc3_device_t *device = (hw_ostc3_device_t*) abstract; dc_status_t rc = DC_STATUS_SUCCESS; @@ -438,22 +439,19 @@ hw_ostc3_device_close (dc_device_t *abstract) rc = hw_ostc3_transfer (device, NULL, EXIT, NULL, 0, NULL, 0); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - serial_close (device->port); - free (device); - return rc; + dc_status_set_error(&status, rc); } } // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/irda.c b/src/irda.c index 3903b7b..3be1151 100644 --- a/src/irda.c +++ b/src/irda.c @@ -133,6 +133,8 @@ error_free: int irda_socket_close (irda_t *device) { + int errcode = 0; + if (device == NULL) return -1; @@ -146,26 +148,21 @@ irda_socket_close (irda_t *device) if (close (device->fd) != 0) { #endif SYSERROR (device->context, ERRNO); -#ifdef _WIN32 - WSACleanup (); -#endif - free (device); - return -1; + errcode = -1; } #ifdef _WIN32 // Terminate the winsock dll. if (WSACleanup () != 0) { SYSERROR (device->context, ERRNO); - free (device); - return -1; + errcode = -1; } #endif // Free memory. free (device); - return 0; + return errcode; } diff --git a/src/mares_darwin.c b/src/mares_darwin.c index 1113a46..5ab153d 100644 --- a/src/mares_darwin.c +++ b/src/mares_darwin.c @@ -173,18 +173,18 @@ error_free: static dc_status_t mares_darwin_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; mares_darwin_device_t *device = (mares_darwin_device_t *) abstract; // Close the device. if (serial_close (device->base.port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/mares_iconhd.c b/src/mares_iconhd.c index af6b1de..488852c 100644 --- a/src/mares_iconhd.c +++ b/src/mares_iconhd.c @@ -324,18 +324,18 @@ error_free: static dc_status_t mares_iconhd_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; mares_iconhd_device_t *device = (mares_iconhd_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/mares_nemo.c b/src/mares_nemo.c index 840c27e..2b40905 100644 --- a/src/mares_nemo.c +++ b/src/mares_nemo.c @@ -159,18 +159,18 @@ error_free: static dc_status_t mares_nemo_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; mares_nemo_device_t *device = (mares_nemo_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/mares_puck.c b/src/mares_puck.c index 2b85b9f..07448c0 100644 --- a/src/mares_puck.c +++ b/src/mares_puck.c @@ -181,18 +181,18 @@ error_free: static dc_status_t mares_puck_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; mares_puck_device_t *device = (mares_puck_device_t*) abstract; // Close the device. if (serial_close (device->base.port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index c009ab1..26f6fd3 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -651,6 +651,7 @@ error_free: static dc_status_t oceanic_atom2_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; oceanic_atom2_device_t *device = (oceanic_atom2_device_t*) abstract; // Send the quit command. @@ -658,14 +659,13 @@ oceanic_atom2_device_close (dc_device_t *abstract) // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/oceanic_veo250.c b/src/oceanic_veo250.c index b21f6a0..d2b5d6e 100644 --- a/src/oceanic_veo250.c +++ b/src/oceanic_veo250.c @@ -314,6 +314,7 @@ error_free: static dc_status_t oceanic_veo250_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; oceanic_veo250_device_t *device = (oceanic_veo250_device_t*) abstract; // Switch the device back to surface mode. @@ -321,14 +322,13 @@ oceanic_veo250_device_close (dc_device_t *abstract) // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/oceanic_vtpro.c b/src/oceanic_vtpro.c index 92faf7a..0bce08e 100644 --- a/src/oceanic_vtpro.c +++ b/src/oceanic_vtpro.c @@ -357,6 +357,7 @@ error_free: static dc_status_t oceanic_vtpro_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t*) abstract; // Switch the device back to surface mode. @@ -364,14 +365,13 @@ oceanic_vtpro_device_close (dc_device_t *abstract) // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/reefnet_sensus.c b/src/reefnet_sensus.c index ec0ee07..c4cc685 100644 --- a/src/reefnet_sensus.c +++ b/src/reefnet_sensus.c @@ -154,6 +154,7 @@ error_free: static dc_status_t reefnet_sensus_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; reefnet_sensus_device_t *device = (reefnet_sensus_device_t*) abstract; // Safely close the connection if the last handshake was @@ -163,14 +164,13 @@ reefnet_sensus_device_close (dc_device_t *abstract) // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/reefnet_sensuspro.c b/src/reefnet_sensuspro.c index d20f432..f1bb9ca 100644 --- a/src/reefnet_sensuspro.c +++ b/src/reefnet_sensuspro.c @@ -132,18 +132,18 @@ error_free: static dc_status_t reefnet_sensuspro_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; reefnet_sensuspro_device_t *device = (reefnet_sensuspro_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/reefnet_sensusultra.c b/src/reefnet_sensusultra.c index f16c535..c52d7b3 100644 --- a/src/reefnet_sensusultra.c +++ b/src/reefnet_sensusultra.c @@ -141,18 +141,18 @@ error_free: static dc_status_t reefnet_sensusultra_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; reefnet_sensusultra_device_t *device = (reefnet_sensusultra_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/serial_posix.c b/src/serial_posix.c index ee9312f..ffd4047 100644 --- a/src/serial_posix.c +++ b/src/serial_posix.c @@ -195,15 +195,15 @@ error_free: int serial_close (serial_t *device) { + int errcode = 0; + if (device == NULL) return 0; // Restore the initial terminal attributes. if (tcsetattr (device->fd, TCSANOW, &device->tty) != 0) { SYSERROR (device->context, errno); - close (device->fd); - free (device); - return -1; + errcode = -1; } #ifndef ENABLE_PTY @@ -214,14 +214,13 @@ serial_close (serial_t *device) // Close the device. if (close (device->fd) != 0) { SYSERROR (device->context, errno); - free (device); - return -1; + errcode = -1; } // Free memory. free (device); - return 0; + return errcode; } // diff --git a/src/serial_win32.c b/src/serial_win32.c index 00aeb4d..56c3866 100644 --- a/src/serial_win32.c +++ b/src/serial_win32.c @@ -181,6 +181,8 @@ error_free: int serial_close (serial_t *device) { + int errcode = 0; + if (device == NULL) return 0; @@ -188,22 +190,19 @@ serial_close (serial_t *device) if (!SetCommState (device->hFile, &device->dcb) || !SetCommTimeouts (device->hFile, &device->timeouts)) { SYSERROR (device->context, GetLastError ()); - CloseHandle (device->hFile); - free (device); - return -1; + errcode = -1; } // Close the device. if (!CloseHandle (device->hFile)) { SYSERROR (device->context, GetLastError ()); - free (device); - return -1; + errcode = -1; } // Free memory. free (device); - return 0; + return errcode; } // diff --git a/src/suunto_d9.c b/src/suunto_d9.c index c0903bb..708070a 100644 --- a/src/suunto_d9.c +++ b/src/suunto_d9.c @@ -215,18 +215,18 @@ error_free: static dc_status_t suunto_d9_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; suunto_d9_device_t *device = (suunto_d9_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/suunto_eon.c b/src/suunto_eon.c index e71e315..01b2743 100644 --- a/src/suunto_eon.c +++ b/src/suunto_eon.c @@ -135,18 +135,18 @@ error_free: static dc_status_t suunto_eon_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; suunto_eon_device_t *device = (suunto_eon_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/suunto_solution.c b/src/suunto_solution.c index 421a090..2a2e8de 100644 --- a/src/suunto_solution.c +++ b/src/suunto_solution.c @@ -129,18 +129,18 @@ error_free: static dc_status_t suunto_solution_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; suunto_solution_device_t *device = (suunto_solution_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/suunto_vyper.c b/src/suunto_vyper.c index 03fbc4a..a6bbfc1 100644 --- a/src/suunto_vyper.c +++ b/src/suunto_vyper.c @@ -161,18 +161,18 @@ error_free: static dc_status_t suunto_vyper_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; suunto_vyper_device_t *device = (suunto_vyper_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/suunto_vyper2.c b/src/suunto_vyper2.c index efba846..66d3859 100644 --- a/src/suunto_vyper2.c +++ b/src/suunto_vyper2.c @@ -167,18 +167,18 @@ error_free: static dc_status_t suunto_vyper2_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; suunto_vyper2_device_t *device = (suunto_vyper2_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/uwatec_aladin.c b/src/uwatec_aladin.c index 796e867..d4b1c83 100644 --- a/src/uwatec_aladin.c +++ b/src/uwatec_aladin.c @@ -142,18 +142,18 @@ error_free: static dc_status_t uwatec_aladin_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; uwatec_aladin_device_t *device = (uwatec_aladin_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/uwatec_memomouse.c b/src/uwatec_memomouse.c index 9608cb5..12fc7a8 100644 --- a/src/uwatec_memomouse.c +++ b/src/uwatec_memomouse.c @@ -141,18 +141,18 @@ error_free: static dc_status_t uwatec_memomouse_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; uwatec_memomouse_device_t *device = (uwatec_memomouse_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/uwatec_meridian.c b/src/uwatec_meridian.c index 4828a32..3689592 100644 --- a/src/uwatec_meridian.c +++ b/src/uwatec_meridian.c @@ -252,18 +252,18 @@ error_free: static dc_status_t uwatec_meridian_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; uwatec_meridian_device_t *device = (uwatec_meridian_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/uwatec_smart.c b/src/uwatec_smart.c index 2b327ba..7d27cb5 100644 --- a/src/uwatec_smart.c +++ b/src/uwatec_smart.c @@ -216,18 +216,18 @@ error_free: static dc_status_t uwatec_smart_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; uwatec_smart_device_t *device = (uwatec_smart_device_t*) abstract; // Close the device. if (irda_socket_close (device->socket) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } diff --git a/src/zeagle_n2ition3.c b/src/zeagle_n2ition3.c index a98825a..2559a5a 100644 --- a/src/zeagle_n2ition3.c +++ b/src/zeagle_n2ition3.c @@ -201,18 +201,18 @@ error_free: static dc_status_t zeagle_n2ition3_device_close (dc_device_t *abstract) { + dc_status_t status = DC_STATUS_SUCCESS; zeagle_n2ition3_device_t *device = (zeagle_n2ition3_device_t*) abstract; // Close the device. if (serial_close (device->port) == -1) { - free (device); - return DC_STATUS_IO; + dc_status_set_error(&status, DC_STATUS_IO); } // Free memory. free (device); - return DC_STATUS_SUCCESS; + return status; } From 9bc14dca10e02f6862ad0131dabda5aed99ba56f Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sat, 14 Nov 2015 11:33:46 +0100 Subject: [PATCH 23/45] Remove some boilerplate code from the cleanup functions. Instead of freeing the object data structure in the backend specific cleanup function, the memory is now freed automatically in the base class function. This reduces the amount of boilerplate code in the backends. Backends that don't allocate any additional resources, do no longer require a cleanup function at all. --- src/atomics_cobalt.c | 3 --- src/atomics_cobalt_parser.c | 13 +------------ src/citizen_aqualand.c | 3 --- src/citizen_aqualand_parser.c | 13 +------------ src/cressi_edy.c | 3 --- src/cressi_edy_parser.c | 13 +------------ src/cressi_leonardo.c | 3 --- src/cressi_leonardo_parser.c | 13 +------------ src/device.c | 13 +++++++++---- src/diverite_nitekq.c | 3 --- src/diverite_nitekq_parser.c | 13 +------------ src/divesystem_idive.c | 3 --- src/divesystem_idive_parser.c | 13 +------------ src/hw_frog.c | 3 --- src/hw_ostc.c | 3 --- src/hw_ostc3.c | 3 --- src/hw_ostc_parser.c | 13 +------------ src/mares_darwin.c | 3 --- src/mares_darwin_parser.c | 13 +------------ src/mares_iconhd.c | 3 --- src/mares_iconhd_parser.c | 13 +------------ src/mares_nemo.c | 3 --- src/mares_nemo_parser.c | 13 +------------ src/mares_puck.c | 3 --- src/oceanic_atom2.c | 3 --- src/oceanic_atom2_parser.c | 13 +------------ src/oceanic_veo250.c | 3 --- src/oceanic_veo250_parser.c | 13 +------------ src/oceanic_vtpro.c | 3 --- src/oceanic_vtpro_parser.c | 13 +------------ src/parser.c | 11 ++++++++--- src/reefnet_sensus.c | 3 --- src/reefnet_sensus_parser.c | 13 +------------ src/reefnet_sensuspro.c | 3 --- src/reefnet_sensuspro_parser.c | 13 +------------ src/reefnet_sensusultra.c | 3 --- src/reefnet_sensusultra_parser.c | 13 +------------ src/shearwater_petrel.c | 8 +------- src/shearwater_predator.c | 9 +-------- src/shearwater_predator_parser.c | 15 ++------------- src/suunto_d9.c | 3 --- src/suunto_d9_parser.c | 13 +------------ src/suunto_eon.c | 3 --- src/suunto_eon_parser.c | 13 +------------ src/suunto_eonsteel.c | 1 - src/suunto_eonsteel_parser.c | 2 +- src/suunto_solution.c | 3 --- src/suunto_solution_parser.c | 13 +------------ src/suunto_vyper.c | 3 --- src/suunto_vyper2.c | 3 --- src/suunto_vyper_parser.c | 13 +------------ src/uwatec_aladin.c | 3 --- src/uwatec_memomouse.c | 3 --- src/uwatec_memomouse_parser.c | 13 +------------ src/uwatec_meridian.c | 3 --- src/uwatec_smart.c | 3 --- src/uwatec_smart_parser.c | 13 +------------ src/zeagle_n2ition3.c | 3 --- 58 files changed, 44 insertions(+), 388 deletions(-) diff --git a/src/atomics_cobalt.c b/src/atomics_cobalt.c index b901f5b..184c633 100644 --- a/src/atomics_cobalt.c +++ b/src/atomics_cobalt.c @@ -162,9 +162,6 @@ atomics_cobalt_device_close (dc_device_t *abstract) libusb_exit (device->context); #endif - // Free memory. - free (device); - return DC_STATUS_SUCCESS; } diff --git a/src/atomics_cobalt_parser.c b/src/atomics_cobalt_parser.c index bf4adcb..a14e539 100644 --- a/src/atomics_cobalt_parser.c +++ b/src/atomics_cobalt_parser.c @@ -48,7 +48,6 @@ static dc_status_t atomics_cobalt_parser_set_data (dc_parser_t *abstract, const static dc_status_t atomics_cobalt_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t atomics_cobalt_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t atomics_cobalt_parser_vtable = { DC_FAMILY_ATOMICS_COBALT, @@ -56,7 +55,7 @@ static const dc_parser_vtable_t atomics_cobalt_parser_vtable = { atomics_cobalt_parser_get_datetime, /* datetime */ atomics_cobalt_parser_get_field, /* fields */ atomics_cobalt_parser_samples_foreach, /* samples_foreach */ - atomics_cobalt_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -86,16 +85,6 @@ atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context) } -static dc_status_t -atomics_cobalt_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t atomics_cobalt_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/citizen_aqualand.c b/src/citizen_aqualand.c index cda3dbc..dc3e9d7 100644 --- a/src/citizen_aqualand.c +++ b/src/citizen_aqualand.c @@ -133,9 +133,6 @@ citizen_aqualand_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/citizen_aqualand_parser.c b/src/citizen_aqualand_parser.c index e9c2659..fd96c79 100644 --- a/src/citizen_aqualand_parser.c +++ b/src/citizen_aqualand_parser.c @@ -40,7 +40,6 @@ static dc_status_t citizen_aqualand_parser_set_data (dc_parser_t *abstract, cons static dc_status_t citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t citizen_aqualand_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t citizen_aqualand_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t citizen_aqualand_parser_vtable = { DC_FAMILY_CITIZEN_AQUALAND, @@ -48,7 +47,7 @@ static const dc_parser_vtable_t citizen_aqualand_parser_vtable = { citizen_aqualand_parser_get_datetime, /* datetime */ citizen_aqualand_parser_get_field, /* fields */ citizen_aqualand_parser_samples_foreach, /* samples_foreach */ - citizen_aqualand_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -74,16 +73,6 @@ citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context) } -static dc_status_t -citizen_aqualand_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t citizen_aqualand_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/cressi_edy.c b/src/cressi_edy.c index e58619b..3bc72c0 100644 --- a/src/cressi_edy.c +++ b/src/cressi_edy.c @@ -342,9 +342,6 @@ cressi_edy_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/cressi_edy_parser.c b/src/cressi_edy_parser.c index 59898f6..6777081 100644 --- a/src/cressi_edy_parser.c +++ b/src/cressi_edy_parser.c @@ -43,7 +43,6 @@ static dc_status_t cressi_edy_parser_set_data (dc_parser_t *abstract, const unsi static dc_status_t cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t cressi_edy_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t cressi_edy_parser_vtable = { DC_FAMILY_CRESSI_EDY, @@ -51,7 +50,7 @@ static const dc_parser_vtable_t cressi_edy_parser_vtable = { cressi_edy_parser_get_datetime, /* datetime */ cressi_edy_parser_get_field, /* fields */ cressi_edy_parser_samples_foreach, /* samples_foreach */ - cressi_edy_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -95,16 +94,6 @@ cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int } -static dc_status_t -cressi_edy_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t cressi_edy_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/cressi_leonardo.c b/src/cressi_leonardo.c index 6ca321d..2c9045e 100644 --- a/src/cressi_leonardo.c +++ b/src/cressi_leonardo.c @@ -150,9 +150,6 @@ cressi_leonardo_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/cressi_leonardo_parser.c b/src/cressi_leonardo_parser.c index b01a37a..ceced18 100644 --- a/src/cressi_leonardo_parser.c +++ b/src/cressi_leonardo_parser.c @@ -41,7 +41,6 @@ static dc_status_t cressi_leonardo_parser_set_data (dc_parser_t *abstract, const static dc_status_t cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t cressi_leonardo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t cressi_leonardo_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t cressi_leonardo_parser_vtable = { DC_FAMILY_CRESSI_EDY, @@ -49,7 +48,7 @@ static const dc_parser_vtable_t cressi_leonardo_parser_vtable = { cressi_leonardo_parser_get_datetime, /* datetime */ cressi_leonardo_parser_get_field, /* fields */ cressi_leonardo_parser_samples_foreach, /* samples_foreach */ - cressi_leonardo_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -75,16 +74,6 @@ cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context) } -static dc_status_t -cressi_leonardo_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t cressi_leonardo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/device.c b/src/device.c index 504b8cf..8758480 100644 --- a/src/device.c +++ b/src/device.c @@ -327,17 +327,22 @@ dc_device_foreach (dc_device_t *device, dc_dive_callback_t callback, void *userd dc_status_t dc_device_close (dc_device_t *device) { + dc_status_t status = DC_STATUS_SUCCESS; + if (device == NULL) return DC_STATUS_SUCCESS; - if (device->vtable->close == NULL) - return DC_STATUS_UNSUPPORTED; - // Disable the cancellation callback. device->cancel_callback = NULL; device->cancel_userdata = NULL; - return device->vtable->close (device); + if (device->vtable->close) { + status = device->vtable->close (device); + } + + free (device); + + return status; } diff --git a/src/diverite_nitekq.c b/src/diverite_nitekq.c index 1d8b96a..fc819a1 100644 --- a/src/diverite_nitekq.c +++ b/src/diverite_nitekq.c @@ -229,9 +229,6 @@ diverite_nitekq_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/diverite_nitekq_parser.c b/src/diverite_nitekq_parser.c index f65ba38..a32efa1 100644 --- a/src/diverite_nitekq_parser.c +++ b/src/diverite_nitekq_parser.c @@ -52,7 +52,6 @@ static dc_status_t diverite_nitekq_parser_set_data (dc_parser_t *abstract, const static dc_status_t diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t diverite_nitekq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t diverite_nitekq_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t diverite_nitekq_parser_vtable = { DC_FAMILY_DIVERITE_NITEKQ, @@ -60,7 +59,7 @@ static const dc_parser_vtable_t diverite_nitekq_parser_vtable = { diverite_nitekq_parser_get_datetime, /* datetime */ diverite_nitekq_parser_get_field, /* fields */ diverite_nitekq_parser_samples_foreach, /* samples_foreach */ - diverite_nitekq_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -97,16 +96,6 @@ diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context) } -static dc_status_t -diverite_nitekq_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t diverite_nitekq_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/divesystem_idive.c b/src/divesystem_idive.c index e4eec6a..9565386 100644 --- a/src/divesystem_idive.c +++ b/src/divesystem_idive.c @@ -181,9 +181,6 @@ divesystem_idive_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/divesystem_idive_parser.c b/src/divesystem_idive_parser.c index 81d1b3d..5ea2052 100644 --- a/src/divesystem_idive_parser.c +++ b/src/divesystem_idive_parser.c @@ -62,7 +62,6 @@ static dc_status_t divesystem_idive_parser_set_data (dc_parser_t *abstract, cons static dc_status_t divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t divesystem_idive_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t divesystem_idive_parser_vtable = { DC_FAMILY_DIVESYSTEM_IDIVE, @@ -70,7 +69,7 @@ static const dc_parser_vtable_t divesystem_idive_parser_vtable = { divesystem_idive_parser_get_datetime, /* datetime */ divesystem_idive_parser_get_field, /* fields */ divesystem_idive_parser_samples_foreach, /* samples_foreach */ - divesystem_idive_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -120,16 +119,6 @@ divesystem_idive_parser_create2 (dc_parser_t **out, dc_context_t *context, unsig } -static dc_status_t -divesystem_idive_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/hw_frog.c b/src/hw_frog.c index 48c9175..339c5ef 100644 --- a/src/hw_frog.c +++ b/src/hw_frog.c @@ -287,9 +287,6 @@ hw_frog_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/hw_ostc.c b/src/hw_ostc.c index 42dc778..d69c3df 100644 --- a/src/hw_ostc.c +++ b/src/hw_ostc.c @@ -195,9 +195,6 @@ hw_ostc_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index 20cbe8d..a2befa0 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -448,9 +448,6 @@ hw_ostc3_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index 5a6d02f..5ee2097 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -97,7 +97,6 @@ static dc_status_t hw_ostc_parser_set_data (dc_parser_t *abstract, const unsigne static dc_status_t hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t hw_ostc_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t hw_ostc_parser_vtable = { DC_FAMILY_HW_OSTC, @@ -105,7 +104,7 @@ static const dc_parser_vtable_t hw_ostc_parser_vtable = { hw_ostc_parser_get_datetime, /* datetime */ hw_ostc_parser_get_field, /* fields */ hw_ostc_parser_samples_foreach, /* samples_foreach */ - hw_ostc_parser_destroy /* destroy */ + NULL /* destroy */ }; static const hw_ostc_layout_t hw_ostc_layout_ostc = { @@ -300,16 +299,6 @@ hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int fr } -static dc_status_t -hw_ostc_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t hw_ostc_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/mares_darwin.c b/src/mares_darwin.c index 5ab153d..d12172f 100644 --- a/src/mares_darwin.c +++ b/src/mares_darwin.c @@ -181,9 +181,6 @@ mares_darwin_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/mares_darwin_parser.c b/src/mares_darwin_parser.c index 5de4c4b..67ae51c 100644 --- a/src/mares_darwin_parser.c +++ b/src/mares_darwin_parser.c @@ -47,7 +47,6 @@ static dc_status_t mares_darwin_parser_set_data (dc_parser_t *abstract, const un static dc_status_t mares_darwin_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t mares_darwin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t mares_darwin_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t mares_darwin_parser_vtable = { DC_FAMILY_MARES_DARWIN, @@ -55,7 +54,7 @@ static const dc_parser_vtable_t mares_darwin_parser_vtable = { mares_darwin_parser_get_datetime, /* datetime */ mares_darwin_parser_get_field, /* fields */ mares_darwin_parser_samples_foreach, /* samples_foreach */ - mares_darwin_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -91,16 +90,6 @@ mares_darwin_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i } -static dc_status_t -mares_darwin_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t mares_darwin_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/mares_iconhd.c b/src/mares_iconhd.c index 488852c..123b103 100644 --- a/src/mares_iconhd.c +++ b/src/mares_iconhd.c @@ -332,9 +332,6 @@ mares_iconhd_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/mares_iconhd_parser.c b/src/mares_iconhd_parser.c index 51b1fd4..728162e 100644 --- a/src/mares_iconhd_parser.c +++ b/src/mares_iconhd_parser.c @@ -60,7 +60,6 @@ static dc_status_t mares_iconhd_parser_set_data (dc_parser_t *abstract, const un static dc_status_t mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t mares_iconhd_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t mares_iconhd_parser_vtable = { DC_FAMILY_MARES_ICONHD, @@ -68,7 +67,7 @@ static const dc_parser_vtable_t mares_iconhd_parser_vtable = { mares_iconhd_parser_get_datetime, /* datetime */ mares_iconhd_parser_get_field, /* fields */ mares_iconhd_parser_samples_foreach, /* samples_foreach */ - mares_iconhd_parser_destroy /* destroy */ + NULL /* destroy */ }; static dc_status_t @@ -229,16 +228,6 @@ mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i } -static dc_status_t -mares_iconhd_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t mares_iconhd_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/mares_nemo.c b/src/mares_nemo.c index 2b40905..e6a1bb8 100644 --- a/src/mares_nemo.c +++ b/src/mares_nemo.c @@ -167,9 +167,6 @@ mares_nemo_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/mares_nemo_parser.c b/src/mares_nemo_parser.c index b997ae4..487b5f2 100644 --- a/src/mares_nemo_parser.c +++ b/src/mares_nemo_parser.c @@ -63,7 +63,6 @@ static dc_status_t mares_nemo_parser_set_data (dc_parser_t *abstract, const unsi static dc_status_t mares_nemo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t mares_nemo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t mares_nemo_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t mares_nemo_parser_vtable = { DC_FAMILY_MARES_NEMO, @@ -71,7 +70,7 @@ static const dc_parser_vtable_t mares_nemo_parser_vtable = { mares_nemo_parser_get_datetime, /* datetime */ mares_nemo_parser_get_field, /* fields */ mares_nemo_parser_samples_foreach, /* samples_foreach */ - mares_nemo_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -112,16 +111,6 @@ mares_nemo_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int } -static dc_status_t -mares_nemo_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t mares_nemo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/mares_puck.c b/src/mares_puck.c index 07448c0..95ba855 100644 --- a/src/mares_puck.c +++ b/src/mares_puck.c @@ -189,9 +189,6 @@ mares_puck_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 26f6fd3..93aa5da 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -662,9 +662,6 @@ oceanic_atom2_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 99d5602..a6f39ec 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -107,7 +107,6 @@ static dc_status_t oceanic_atom2_parser_set_data (dc_parser_t *abstract, const u static dc_status_t oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t oceanic_atom2_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t oceanic_atom2_parser_vtable = { DC_FAMILY_OCEANIC_ATOM2, @@ -115,7 +114,7 @@ static const dc_parser_vtable_t oceanic_atom2_parser_vtable = { oceanic_atom2_parser_get_datetime, /* datetime */ oceanic_atom2_parser_get_field, /* fields */ oceanic_atom2_parser_samples_foreach, /* samples_foreach */ - oceanic_atom2_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -180,16 +179,6 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned } -static dc_status_t -oceanic_atom2_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t oceanic_atom2_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/oceanic_veo250.c b/src/oceanic_veo250.c index d2b5d6e..15d8070 100644 --- a/src/oceanic_veo250.c +++ b/src/oceanic_veo250.c @@ -325,9 +325,6 @@ oceanic_veo250_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/oceanic_veo250_parser.c b/src/oceanic_veo250_parser.c index 36eeeb4..4cc8ebe 100644 --- a/src/oceanic_veo250_parser.c +++ b/src/oceanic_veo250_parser.c @@ -51,7 +51,6 @@ static dc_status_t oceanic_veo250_parser_set_data (dc_parser_t *abstract, const static dc_status_t oceanic_veo250_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t oceanic_veo250_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t oceanic_veo250_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t oceanic_veo250_parser_vtable = { DC_FAMILY_OCEANIC_VEO250, @@ -59,7 +58,7 @@ static const dc_parser_vtable_t oceanic_veo250_parser_vtable = { oceanic_veo250_parser_get_datetime, /* datetime */ oceanic_veo250_parser_get_field, /* fields */ oceanic_veo250_parser_samples_foreach, /* samples_foreach */ - oceanic_veo250_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -91,16 +90,6 @@ oceanic_veo250_parser_create (dc_parser_t **out, dc_context_t *context, unsigned } -static dc_status_t -oceanic_veo250_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t oceanic_veo250_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/oceanic_vtpro.c b/src/oceanic_vtpro.c index 0bce08e..67867b7 100644 --- a/src/oceanic_vtpro.c +++ b/src/oceanic_vtpro.c @@ -368,9 +368,6 @@ oceanic_vtpro_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/oceanic_vtpro_parser.c b/src/oceanic_vtpro_parser.c index f7d2be5..c1b5150 100644 --- a/src/oceanic_vtpro_parser.c +++ b/src/oceanic_vtpro_parser.c @@ -45,7 +45,6 @@ static dc_status_t oceanic_vtpro_parser_set_data (dc_parser_t *abstract, const u static dc_status_t oceanic_vtpro_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t oceanic_vtpro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t oceanic_vtpro_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t oceanic_vtpro_parser_vtable = { DC_FAMILY_OCEANIC_VTPRO, @@ -53,7 +52,7 @@ static const dc_parser_vtable_t oceanic_vtpro_parser_vtable = { oceanic_vtpro_parser_get_datetime, /* datetime */ oceanic_vtpro_parser_get_field, /* fields */ oceanic_vtpro_parser_samples_foreach, /* samples_foreach */ - oceanic_vtpro_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -84,16 +83,6 @@ oceanic_vtpro_parser_create (dc_parser_t **out, dc_context_t *context) } -static dc_status_t -oceanic_vtpro_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t oceanic_vtpro_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/parser.c b/src/parser.c index 5f9a7a7..bc6b406 100644 --- a/src/parser.c +++ b/src/parser.c @@ -239,13 +239,18 @@ dc_parser_samples_foreach (dc_parser_t *parser, dc_sample_callback_t callback, v dc_status_t dc_parser_destroy (dc_parser_t *parser) { + dc_status_t status = DC_STATUS_SUCCESS; + if (parser == NULL) return DC_STATUS_SUCCESS; - if (parser->vtable->destroy == NULL) - return DC_STATUS_UNSUPPORTED; + if (parser->vtable->destroy) { + status = parser->vtable->destroy (parser); + } - return parser->vtable->destroy (parser); + free (parser); + + return status; } diff --git a/src/reefnet_sensus.c b/src/reefnet_sensus.c index c4cc685..ba40ee5 100644 --- a/src/reefnet_sensus.c +++ b/src/reefnet_sensus.c @@ -167,9 +167,6 @@ reefnet_sensus_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/reefnet_sensus_parser.c b/src/reefnet_sensus_parser.c index 9b5de72..b5702f2 100644 --- a/src/reefnet_sensus_parser.c +++ b/src/reefnet_sensus_parser.c @@ -52,7 +52,6 @@ static dc_status_t reefnet_sensus_parser_set_data (dc_parser_t *abstract, const static dc_status_t reefnet_sensus_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t reefnet_sensus_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t reefnet_sensus_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t reefnet_sensus_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t reefnet_sensus_parser_vtable = { DC_FAMILY_REEFNET_SENSUS, @@ -60,7 +59,7 @@ static const dc_parser_vtable_t reefnet_sensus_parser_vtable = { reefnet_sensus_parser_get_datetime, /* datetime */ reefnet_sensus_parser_get_field, /* fields */ reefnet_sensus_parser_samples_foreach, /* samples_foreach */ - reefnet_sensus_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -95,16 +94,6 @@ reefnet_sensus_parser_create (dc_parser_t **out, dc_context_t *context, unsigned } -static dc_status_t -reefnet_sensus_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t reefnet_sensus_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/reefnet_sensuspro.c b/src/reefnet_sensuspro.c index f1bb9ca..1063166 100644 --- a/src/reefnet_sensuspro.c +++ b/src/reefnet_sensuspro.c @@ -140,9 +140,6 @@ reefnet_sensuspro_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/reefnet_sensuspro_parser.c b/src/reefnet_sensuspro_parser.c index 0f3af95..cc9d999 100644 --- a/src/reefnet_sensuspro_parser.c +++ b/src/reefnet_sensuspro_parser.c @@ -51,7 +51,6 @@ static dc_status_t reefnet_sensuspro_parser_set_data (dc_parser_t *abstract, con static dc_status_t reefnet_sensuspro_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t reefnet_sensuspro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t reefnet_sensuspro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t reefnet_sensuspro_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t reefnet_sensuspro_parser_vtable = { DC_FAMILY_REEFNET_SENSUSPRO, @@ -59,7 +58,7 @@ static const dc_parser_vtable_t reefnet_sensuspro_parser_vtable = { reefnet_sensuspro_parser_get_datetime, /* datetime */ reefnet_sensuspro_parser_get_field, /* fields */ reefnet_sensuspro_parser_samples_foreach, /* samples_foreach */ - reefnet_sensuspro_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -94,16 +93,6 @@ reefnet_sensuspro_parser_create (dc_parser_t **out, dc_context_t *context, unsig } -static dc_status_t -reefnet_sensuspro_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t reefnet_sensuspro_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/reefnet_sensusultra.c b/src/reefnet_sensusultra.c index c52d7b3..d246c14 100644 --- a/src/reefnet_sensusultra.c +++ b/src/reefnet_sensusultra.c @@ -149,9 +149,6 @@ reefnet_sensusultra_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/reefnet_sensusultra_parser.c b/src/reefnet_sensusultra_parser.c index 1d85b06..339fa0d 100644 --- a/src/reefnet_sensusultra_parser.c +++ b/src/reefnet_sensusultra_parser.c @@ -51,7 +51,6 @@ static dc_status_t reefnet_sensusultra_parser_set_data (dc_parser_t *abstract, c static dc_status_t reefnet_sensusultra_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t reefnet_sensusultra_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t reefnet_sensusultra_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t reefnet_sensusultra_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t reefnet_sensusultra_parser_vtable = { DC_FAMILY_REEFNET_SENSUSULTRA, @@ -59,7 +58,7 @@ static const dc_parser_vtable_t reefnet_sensusultra_parser_vtable = { reefnet_sensusultra_parser_get_datetime, /* datetime */ reefnet_sensusultra_parser_get_field, /* fields */ reefnet_sensusultra_parser_samples_foreach, /* samples_foreach */ - reefnet_sensusultra_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -94,16 +93,6 @@ reefnet_sensusultra_parser_create (dc_parser_t **out, dc_context_t *context, uns } -static dc_status_t -reefnet_sensusultra_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t reefnet_sensusultra_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/shearwater_petrel.c b/src/shearwater_petrel.c index 1bf98f5..f5e6d76 100644 --- a/src/shearwater_petrel.c +++ b/src/shearwater_petrel.c @@ -117,7 +117,6 @@ error_free: static dc_status_t shearwater_petrel_device_close (dc_device_t *abstract) { - dc_status_t rc = DC_STATUS_SUCCESS; shearwater_common_device_t *device = (shearwater_common_device_t *) abstract; // Shutdown the device. @@ -125,12 +124,7 @@ shearwater_petrel_device_close (dc_device_t *abstract) shearwater_common_transfer (device, request, sizeof (request), NULL, 0, NULL); // Close the device. - rc = shearwater_common_close (device); - - // Free memory. - free (device); - - return rc; + return shearwater_common_close (device); } diff --git a/src/shearwater_predator.c b/src/shearwater_predator.c index 7fa6f83..f5cfbc6 100644 --- a/src/shearwater_predator.c +++ b/src/shearwater_predator.c @@ -103,16 +103,9 @@ error_free: static dc_status_t shearwater_predator_device_close (dc_device_t *abstract) { - dc_status_t rc = DC_STATUS_SUCCESS; shearwater_common_device_t *device = (shearwater_common_device_t *) abstract; - // Close the device. - rc = shearwater_common_close (device); - - // Free memory. - free (device); - - return rc; + return shearwater_common_close (device); } diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index 1423e77..cacdcca 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -67,7 +67,6 @@ static dc_status_t shearwater_predator_parser_set_data (dc_parser_t *abstract, c static dc_status_t shearwater_predator_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t shearwater_predator_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t shearwater_predator_parser_vtable = { DC_FAMILY_SHEARWATER_PREDATOR, @@ -75,7 +74,7 @@ static const dc_parser_vtable_t shearwater_predator_parser_vtable = { shearwater_predator_parser_get_datetime, /* datetime */ shearwater_predator_parser_get_field, /* fields */ shearwater_predator_parser_samples_foreach, /* samples_foreach */ - shearwater_predator_parser_destroy /* destroy */ + NULL /* destroy */ }; static const dc_parser_vtable_t shearwater_petrel_parser_vtable = { @@ -84,7 +83,7 @@ static const dc_parser_vtable_t shearwater_petrel_parser_vtable = { shearwater_predator_parser_get_datetime, /* datetime */ shearwater_predator_parser_get_field, /* fields */ shearwater_predator_parser_samples_foreach, /* samples_foreach */ - shearwater_predator_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -155,16 +154,6 @@ shearwater_petrel_parser_create (dc_parser_t **out, dc_context_t *context) } -static dc_status_t -shearwater_predator_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t shearwater_predator_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/suunto_d9.c b/src/suunto_d9.c index 708070a..ce3ff89 100644 --- a/src/suunto_d9.c +++ b/src/suunto_d9.c @@ -223,9 +223,6 @@ suunto_d9_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c index c59ac48..adda93b 100644 --- a/src/suunto_d9_parser.c +++ b/src/suunto_d9_parser.c @@ -83,7 +83,6 @@ static dc_status_t suunto_d9_parser_set_data (dc_parser_t *abstract, const unsig static dc_status_t suunto_d9_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t suunto_d9_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t suunto_d9_parser_vtable = { DC_FAMILY_SUUNTO_D9, @@ -91,7 +90,7 @@ static const dc_parser_vtable_t suunto_d9_parser_vtable = { suunto_d9_parser_get_datetime, /* datetime */ suunto_d9_parser_get_field, /* fields */ suunto_d9_parser_samples_foreach, /* samples_foreach */ - suunto_d9_parser_destroy /* destroy */ + NULL /* destroy */ }; static unsigned int @@ -234,16 +233,6 @@ suunto_d9_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int } -static dc_status_t -suunto_d9_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t suunto_d9_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/suunto_eon.c b/src/suunto_eon.c index 01b2743..306dac5 100644 --- a/src/suunto_eon.c +++ b/src/suunto_eon.c @@ -143,9 +143,6 @@ suunto_eon_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/suunto_eon_parser.c b/src/suunto_eon_parser.c index a803801..be38d7f 100644 --- a/src/suunto_eon_parser.c +++ b/src/suunto_eon_parser.c @@ -47,7 +47,6 @@ static dc_status_t suunto_eon_parser_set_data (dc_parser_t *abstract, const unsi static dc_status_t suunto_eon_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t suunto_eon_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t suunto_eon_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t suunto_eon_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t suunto_eon_parser_vtable = { DC_FAMILY_SUUNTO_EON, @@ -55,7 +54,7 @@ static const dc_parser_vtable_t suunto_eon_parser_vtable = { suunto_eon_parser_get_datetime, /* datetime */ suunto_eon_parser_get_field, /* fields */ suunto_eon_parser_samples_foreach, /* samples_foreach */ - suunto_eon_parser_destroy /* destroy */ + NULL /* destroy */ }; static dc_status_t @@ -138,16 +137,6 @@ suunto_eon_parser_create (dc_parser_t **out, dc_context_t *context, int spyder) } -static dc_status_t -suunto_eon_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t suunto_eon_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/suunto_eonsteel.c b/src/suunto_eonsteel.c index 8bd0350..03b6f99 100644 --- a/src/suunto_eonsteel.c +++ b/src/suunto_eonsteel.c @@ -696,7 +696,6 @@ suunto_eonsteel_device_close(dc_device_t *abstract) libusb_close(eon->handle); libusb_exit(eon->ctx); - free(eon); return DC_STATUS_SUCCESS; } diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index 2e31c90..e638bde 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -1191,7 +1191,7 @@ suunto_eonsteel_parser_destroy(dc_parser_t *parser) suunto_eonsteel_parser_t *eon = (suunto_eonsteel_parser_t *) parser; desc_free(eon->type_desc, MAXTYPE); - free(parser); + return DC_STATUS_SUCCESS; } diff --git a/src/suunto_solution.c b/src/suunto_solution.c index 2a2e8de..3ff1f60 100644 --- a/src/suunto_solution.c +++ b/src/suunto_solution.c @@ -137,9 +137,6 @@ suunto_solution_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/suunto_solution_parser.c b/src/suunto_solution_parser.c index 94e146a..8a6ad62 100644 --- a/src/suunto_solution_parser.c +++ b/src/suunto_solution_parser.c @@ -42,7 +42,6 @@ struct suunto_solution_parser_t { static dc_status_t suunto_solution_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size); static dc_status_t suunto_solution_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t suunto_solution_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t suunto_solution_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t suunto_solution_parser_vtable = { DC_FAMILY_SUUNTO_SOLUTION, @@ -50,7 +49,7 @@ static const dc_parser_vtable_t suunto_solution_parser_vtable = { NULL, /* datetime */ suunto_solution_parser_get_field, /* fields */ suunto_solution_parser_samples_foreach, /* samples_foreach */ - suunto_solution_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -81,16 +80,6 @@ suunto_solution_parser_create (dc_parser_t **out, dc_context_t *context) } -static dc_status_t -suunto_solution_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t suunto_solution_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/suunto_vyper.c b/src/suunto_vyper.c index a6bbfc1..701fbeb 100644 --- a/src/suunto_vyper.c +++ b/src/suunto_vyper.c @@ -169,9 +169,6 @@ suunto_vyper_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/suunto_vyper2.c b/src/suunto_vyper2.c index 66d3859..e701164 100644 --- a/src/suunto_vyper2.c +++ b/src/suunto_vyper2.c @@ -175,9 +175,6 @@ suunto_vyper2_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/suunto_vyper_parser.c b/src/suunto_vyper_parser.c index 4e2d974..4628cb1 100644 --- a/src/suunto_vyper_parser.c +++ b/src/suunto_vyper_parser.c @@ -48,7 +48,6 @@ static dc_status_t suunto_vyper_parser_set_data (dc_parser_t *abstract, const un static dc_status_t suunto_vyper_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t suunto_vyper_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t suunto_vyper_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t suunto_vyper_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t suunto_vyper_parser_vtable = { DC_FAMILY_SUUNTO_VYPER, @@ -56,7 +55,7 @@ static const dc_parser_vtable_t suunto_vyper_parser_vtable = { suunto_vyper_parser_get_datetime, /* datetime */ suunto_vyper_parser_get_field, /* fields */ suunto_vyper_parser_samples_foreach, /* samples_foreach */ - suunto_vyper_parser_destroy /* destroy */ + NULL /* destroy */ }; static unsigned int @@ -190,16 +189,6 @@ suunto_vyper_parser_create (dc_parser_t **out, dc_context_t *context) } -static dc_status_t -suunto_vyper_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t suunto_vyper_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/uwatec_aladin.c b/src/uwatec_aladin.c index d4b1c83..7cd7dff 100644 --- a/src/uwatec_aladin.c +++ b/src/uwatec_aladin.c @@ -150,9 +150,6 @@ uwatec_aladin_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/uwatec_memomouse.c b/src/uwatec_memomouse.c index 12fc7a8..29b2c69 100644 --- a/src/uwatec_memomouse.c +++ b/src/uwatec_memomouse.c @@ -149,9 +149,6 @@ uwatec_memomouse_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/uwatec_memomouse_parser.c b/src/uwatec_memomouse_parser.c index a47cdc4..98fc25d 100644 --- a/src/uwatec_memomouse_parser.c +++ b/src/uwatec_memomouse_parser.c @@ -42,7 +42,6 @@ static dc_status_t uwatec_memomouse_parser_set_data (dc_parser_t *abstract, cons static dc_status_t uwatec_memomouse_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t uwatec_memomouse_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t uwatec_memomouse_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t uwatec_memomouse_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t uwatec_memomouse_parser_vtable = { DC_FAMILY_UWATEC_MEMOMOUSE, @@ -50,7 +49,7 @@ static const dc_parser_vtable_t uwatec_memomouse_parser_vtable = { uwatec_memomouse_parser_get_datetime, /* datetime */ uwatec_memomouse_parser_get_field, /* fields */ uwatec_memomouse_parser_samples_foreach, /* samples_foreach */ - uwatec_memomouse_parser_destroy /* destroy */ + NULL /* destroy */ }; @@ -80,16 +79,6 @@ uwatec_memomouse_parser_create (dc_parser_t **out, dc_context_t *context, unsign } -static dc_status_t -uwatec_memomouse_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t uwatec_memomouse_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/uwatec_meridian.c b/src/uwatec_meridian.c index 3689592..dda19bd 100644 --- a/src/uwatec_meridian.c +++ b/src/uwatec_meridian.c @@ -260,9 +260,6 @@ uwatec_meridian_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/uwatec_smart.c b/src/uwatec_smart.c index 7d27cb5..2d45294 100644 --- a/src/uwatec_smart.c +++ b/src/uwatec_smart.c @@ -224,9 +224,6 @@ uwatec_smart_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index c06e5e2..1fe57d7 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -150,7 +150,6 @@ static dc_status_t uwatec_smart_parser_set_data (dc_parser_t *abstract, const un static dc_status_t uwatec_smart_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t uwatec_smart_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); -static dc_status_t uwatec_smart_parser_destroy (dc_parser_t *abstract); static const dc_parser_vtable_t uwatec_smart_parser_vtable = { DC_FAMILY_UWATEC_SMART, @@ -158,7 +157,7 @@ static const dc_parser_vtable_t uwatec_smart_parser_vtable = { uwatec_smart_parser_get_datetime, /* datetime */ uwatec_smart_parser_get_field, /* fields */ uwatec_smart_parser_samples_foreach, /* samples_foreach */ - uwatec_smart_parser_destroy /* destroy */ + NULL /* destroy */ }; static const @@ -626,16 +625,6 @@ error_free: } -static dc_status_t -uwatec_smart_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; -} - - static dc_status_t uwatec_smart_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { diff --git a/src/zeagle_n2ition3.c b/src/zeagle_n2ition3.c index 2559a5a..ff7f8c2 100644 --- a/src/zeagle_n2ition3.c +++ b/src/zeagle_n2ition3.c @@ -209,9 +209,6 @@ zeagle_n2ition3_device_close (dc_device_t *abstract) dc_status_set_error(&status, DC_STATUS_IO); } - // Free memory. - free (device); - return status; } From ff29d218bbc4b47f3560b444287a6681aa0ae65b Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sat, 14 Nov 2015 12:05:43 +0100 Subject: [PATCH 24/45] Use helper functions to allocate and free objects. Both the allocation and initialization of the object data structure is now moved to a single function. The corresponding deallocation function is intended to free objects that have been allocated, but are not fully initialized yet. The public cleanup function shouldn't be used in such case, because it may try to release resources that haven't been initialized yet. --- src/atomics_cobalt.c | 8 +++----- src/atomics_cobalt_parser.c | 8 ++++---- src/citizen_aqualand.c | 8 +++----- src/citizen_aqualand_parser.c | 8 ++++---- src/cressi_edy.c | 8 +++----- src/cressi_edy_parser.c | 8 ++++---- src/cressi_leonardo.c | 8 +++----- src/cressi_leonardo_parser.c | 8 ++++---- src/device-private.h | 7 ++++++- src/device.c | 27 +++++++++++++++++++++++---- src/diverite_nitekq.c | 8 +++----- src/diverite_nitekq_parser.c | 8 ++++---- src/divesystem_idive.c | 8 +++----- src/divesystem_idive_parser.c | 8 ++++---- src/hw_frog.c | 8 +++----- src/hw_ostc.c | 8 +++----- src/hw_ostc3.c | 8 +++----- src/hw_ostc_parser.c | 8 ++++---- src/mares_common.c | 5 +---- src/mares_common.h | 2 +- src/mares_darwin.c | 7 ++++--- src/mares_darwin_parser.c | 8 ++++---- src/mares_iconhd.c | 8 +++----- src/mares_iconhd_parser.c | 8 ++++---- src/mares_nemo.c | 8 +++----- src/mares_nemo_parser.c | 8 ++++---- src/mares_puck.c | 7 ++++--- src/oceanic_atom2.c | 7 ++++--- src/oceanic_atom2_parser.c | 8 ++++---- src/oceanic_common.c | 5 +---- src/oceanic_common.h | 2 +- src/oceanic_veo250.c | 7 ++++--- src/oceanic_veo250_parser.c | 8 ++++---- src/oceanic_vtpro.c | 7 ++++--- src/oceanic_vtpro_parser.c | 8 ++++---- src/parser-private.h | 7 ++++++- src/parser.c | 28 +++++++++++++++++++++++++--- src/reefnet_sensus.c | 8 +++----- src/reefnet_sensus_parser.c | 8 ++++---- src/reefnet_sensuspro.c | 8 +++----- src/reefnet_sensuspro_parser.c | 8 ++++---- src/reefnet_sensusultra.c | 8 +++----- src/reefnet_sensusultra_parser.c | 8 ++++---- src/shearwater_petrel.c | 8 +++----- src/shearwater_predator.c | 8 +++----- src/shearwater_predator_parser.c | 28 +++++++++++++++++----------- src/suunto_common.c | 5 +---- src/suunto_common.h | 2 +- src/suunto_common2.c | 5 +---- src/suunto_common2.h | 2 +- src/suunto_d9.c | 7 ++++--- src/suunto_d9_parser.c | 8 ++++---- src/suunto_eon.c | 7 ++++--- src/suunto_eon_parser.c | 8 ++++---- src/suunto_eonsteel.c | 8 +++----- src/suunto_eonsteel_parser.c | 14 +++++++++----- src/suunto_solution.c | 8 +++----- src/suunto_solution_parser.c | 8 ++++---- src/suunto_vyper.c | 7 ++++--- src/suunto_vyper2.c | 7 ++++--- src/suunto_vyper_parser.c | 8 ++++---- src/uwatec_aladin.c | 8 +++----- src/uwatec_memomouse.c | 8 +++----- src/uwatec_memomouse_parser.c | 8 ++++---- src/uwatec_meridian.c | 8 +++----- src/uwatec_smart.c | 8 +++----- src/uwatec_smart_parser.c | 8 +++----- src/zeagle_n2ition3.c | 8 +++----- 68 files changed, 286 insertions(+), 276 deletions(-) diff --git a/src/atomics_cobalt.c b/src/atomics_cobalt.c index 184c633..6bc3de2 100644 --- a/src/atomics_cobalt.c +++ b/src/atomics_cobalt.c @@ -69,6 +69,7 @@ static dc_status_t atomics_cobalt_device_foreach (dc_device_t *abstract, dc_dive static dc_status_t atomics_cobalt_device_close (dc_device_t *abstract); static const dc_device_vtable_t atomics_cobalt_device_vtable = { + sizeof(atomics_cobalt_device_t), DC_FAMILY_ATOMICS_COBALT, atomics_cobalt_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -92,15 +93,12 @@ atomics_cobalt_device_open (dc_device_t **out, dc_context_t *context) #ifdef HAVE_LIBUSB // Allocate memory. - device = (atomics_cobalt_device_t *) malloc (sizeof (atomics_cobalt_device_t)); + device = (atomics_cobalt_device_t *) dc_device_allocate (context, &atomics_cobalt_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &atomics_cobalt_device_vtable); - // Set the default values. device->context = NULL; device->handle = NULL; @@ -143,7 +141,7 @@ error_usb_close: error_usb_exit: libusb_exit (device->context); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; #else return DC_STATUS_UNSUPPORTED; diff --git a/src/atomics_cobalt_parser.c b/src/atomics_cobalt_parser.c index a14e539..4bfbcbb 100644 --- a/src/atomics_cobalt_parser.c +++ b/src/atomics_cobalt_parser.c @@ -50,6 +50,7 @@ static dc_status_t atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_fi static dc_status_t atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t atomics_cobalt_parser_vtable = { + sizeof(atomics_cobalt_parser_t), DC_FAMILY_ATOMICS_COBALT, atomics_cobalt_parser_set_data, /* set_data */ atomics_cobalt_parser_get_datetime, /* datetime */ @@ -62,19 +63,18 @@ static const dc_parser_vtable_t atomics_cobalt_parser_vtable = { dc_status_t atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context) { + atomics_cobalt_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - atomics_cobalt_parser_t *parser = (atomics_cobalt_parser_t *) malloc (sizeof (atomics_cobalt_parser_t)); + parser = (atomics_cobalt_parser_t *) dc_parser_allocate (context, &atomics_cobalt_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &atomics_cobalt_parser_vtable); - // Set the default values. parser->atmospheric = 0.0; parser->hydrostatic = 1025.0 * GRAVITY; diff --git a/src/citizen_aqualand.c b/src/citizen_aqualand.c index dc3e9d7..774a3e4 100644 --- a/src/citizen_aqualand.c +++ b/src/citizen_aqualand.c @@ -50,6 +50,7 @@ static dc_status_t citizen_aqualand_device_foreach (dc_device_t *abstract, dc_di static dc_status_t citizen_aqualand_device_close (dc_device_t *abstract); static const dc_device_vtable_t citizen_aqualand_device_vtable = { + sizeof(citizen_aqualand_device_t), DC_FAMILY_CITIZEN_AQUALAND, citizen_aqualand_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -70,15 +71,12 @@ citizen_aqualand_device_open (dc_device_t **out, dc_context_t *context, const ch return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (citizen_aqualand_device_t *) malloc (sizeof (citizen_aqualand_device_t)); + device = (citizen_aqualand_device_t *) dc_device_allocate (context, &citizen_aqualand_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &citizen_aqualand_device_vtable); - // Set the default values. device->port = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); @@ -117,7 +115,7 @@ citizen_aqualand_device_open (dc_device_t **out, dc_context_t *context, const ch error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/citizen_aqualand_parser.c b/src/citizen_aqualand_parser.c index fd96c79..988375b 100644 --- a/src/citizen_aqualand_parser.c +++ b/src/citizen_aqualand_parser.c @@ -42,6 +42,7 @@ static dc_status_t citizen_aqualand_parser_get_field (dc_parser_t *abstract, dc_ static dc_status_t citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t citizen_aqualand_parser_vtable = { + sizeof(citizen_aqualand_parser_t), DC_FAMILY_CITIZEN_AQUALAND, citizen_aqualand_parser_set_data, /* set_data */ citizen_aqualand_parser_get_datetime, /* datetime */ @@ -54,19 +55,18 @@ static const dc_parser_vtable_t citizen_aqualand_parser_vtable = { dc_status_t citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context) { + citizen_aqualand_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - citizen_aqualand_parser_t *parser = (citizen_aqualand_parser_t *) malloc (sizeof (citizen_aqualand_parser_t)); + parser = (citizen_aqualand_parser_t *) dc_parser_allocate (context, &citizen_aqualand_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &citizen_aqualand_parser_vtable); - *out = (dc_parser_t*) parser; return DC_STATUS_SUCCESS; diff --git a/src/cressi_edy.c b/src/cressi_edy.c index 3bc72c0..cfd5f9e 100644 --- a/src/cressi_edy.c +++ b/src/cressi_edy.c @@ -73,6 +73,7 @@ static dc_status_t cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_cal static dc_status_t cressi_edy_device_close (dc_device_t *abstract); static const dc_device_vtable_t cressi_edy_device_vtable = { + sizeof(cressi_edy_device_t), DC_FAMILY_CRESSI_EDY, cressi_edy_device_set_fingerprint, /* set_fingerprint */ cressi_edy_device_read, /* read */ @@ -243,15 +244,12 @@ cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *na return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (cressi_edy_device_t *) malloc (sizeof (cressi_edy_device_t)); + device = (cressi_edy_device_t *) dc_device_allocate (context, &cressi_edy_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &cressi_edy_device_vtable); - // Set the default values. device->port = NULL; device->layout = NULL; @@ -323,7 +321,7 @@ cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *na error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/cressi_edy_parser.c b/src/cressi_edy_parser.c index 6777081..06296f7 100644 --- a/src/cressi_edy_parser.c +++ b/src/cressi_edy_parser.c @@ -45,6 +45,7 @@ static dc_status_t cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_ static dc_status_t cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t cressi_edy_parser_vtable = { + sizeof(cressi_edy_parser_t), DC_FAMILY_CRESSI_EDY, cressi_edy_parser_set_data, /* set_data */ cressi_edy_parser_get_datetime, /* datetime */ @@ -72,19 +73,18 @@ cressi_edy_parser_count_gasmixes (const unsigned char *data) dc_status_t cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model) { + cressi_edy_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - cressi_edy_parser_t *parser = (cressi_edy_parser_t *) malloc (sizeof (cressi_edy_parser_t)); + parser = (cressi_edy_parser_t *) dc_parser_allocate (context, &cressi_edy_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &cressi_edy_parser_vtable); - // Set the default values. parser->model = model; diff --git a/src/cressi_leonardo.c b/src/cressi_leonardo.c index 2c9045e..40a6630 100644 --- a/src/cressi_leonardo.c +++ b/src/cressi_leonardo.c @@ -62,6 +62,7 @@ static dc_status_t cressi_leonardo_device_foreach (dc_device_t *abstract, dc_div static dc_status_t cressi_leonardo_device_close (dc_device_t *abstract); static const dc_device_vtable_t cressi_leonardo_device_vtable = { + sizeof(cressi_leonardo_device_t), DC_FAMILY_CRESSI_LEONARDO, cressi_leonardo_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -81,15 +82,12 @@ cressi_leonardo_device_open (dc_device_t **out, dc_context_t *context, const cha return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (cressi_leonardo_device_t *) malloc (sizeof (cressi_leonardo_device_t)); + device = (cressi_leonardo_device_t *) dc_device_allocate (context, &cressi_leonardo_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &cressi_leonardo_device_vtable); - // Set the default values. device->port = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); @@ -135,7 +133,7 @@ cressi_leonardo_device_open (dc_device_t **out, dc_context_t *context, const cha error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/cressi_leonardo_parser.c b/src/cressi_leonardo_parser.c index ceced18..d9ed79c 100644 --- a/src/cressi_leonardo_parser.c +++ b/src/cressi_leonardo_parser.c @@ -43,6 +43,7 @@ static dc_status_t cressi_leonardo_parser_get_field (dc_parser_t *abstract, dc_f static dc_status_t cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t cressi_leonardo_parser_vtable = { + sizeof(cressi_leonardo_parser_t), DC_FAMILY_CRESSI_EDY, cressi_leonardo_parser_set_data, /* set_data */ cressi_leonardo_parser_get_datetime, /* datetime */ @@ -55,19 +56,18 @@ static const dc_parser_vtable_t cressi_leonardo_parser_vtable = { dc_status_t cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context) { + cressi_leonardo_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - cressi_leonardo_parser_t *parser = (cressi_leonardo_parser_t *) malloc (sizeof (cressi_leonardo_parser_t)); + parser = (cressi_leonardo_parser_t *) dc_parser_allocate (context, &cressi_leonardo_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &cressi_leonardo_parser_vtable); - *out = (dc_parser_t*) parser; return DC_STATUS_SUCCESS; diff --git a/src/device-private.h b/src/device-private.h index 9254c6c..dcf0b96 100644 --- a/src/device-private.h +++ b/src/device-private.h @@ -57,6 +57,8 @@ struct dc_device_t { }; struct dc_device_vtable_t { + size_t size; + dc_family_t type; dc_status_t (*set_fingerprint) (dc_device_t *device, const unsigned char data[], unsigned int size); @@ -75,8 +77,11 @@ struct dc_device_vtable_t { int dc_device_isinstance (dc_device_t *device, const dc_device_vtable_t *vtable); +dc_device_t * +dc_device_allocate (dc_context_t *context, const dc_device_vtable_t *vtable); + void -device_init (dc_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable); +dc_device_deallocate (dc_device_t *device); void device_event_emit (dc_device_t *device, dc_event_type_t event, const void *data); diff --git a/src/device.c b/src/device.c index 8758480..31ec8b8 100644 --- a/src/device.c +++ b/src/device.c @@ -40,10 +40,21 @@ #include "device-private.h" #include "context-private.h" - -void -device_init (dc_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable) +dc_device_t * +dc_device_allocate (dc_context_t *context, const dc_device_vtable_t *vtable) { + dc_device_t *device = NULL; + + assert(vtable != NULL); + assert(vtable->size >= sizeof(dc_device_t)); + + // Allocate memory. + device = (dc_device_t *) malloc (vtable->size); + if (device == NULL) { + ERROR (context, "Failed to allocate memory."); + return device; + } + device->vtable = vtable; device->context = context; @@ -57,6 +68,14 @@ device_init (dc_device_t *device, dc_context_t *context, const dc_device_vtable_ memset (&device->devinfo, 0, sizeof (device->devinfo)); memset (&device->clock, 0, sizeof (device->clock)); + + return device; +} + +void +dc_device_deallocate (dc_device_t *device) +{ + free (device); } dc_status_t @@ -340,7 +359,7 @@ dc_device_close (dc_device_t *device) status = device->vtable->close (device); } - free (device); + dc_device_deallocate (device); return status; } diff --git a/src/diverite_nitekq.c b/src/diverite_nitekq.c index fc819a1..a873424 100644 --- a/src/diverite_nitekq.c +++ b/src/diverite_nitekq.c @@ -68,6 +68,7 @@ static dc_status_t diverite_nitekq_device_foreach (dc_device_t *abstract, dc_div static dc_status_t diverite_nitekq_device_close (dc_device_t *abstract); static const dc_device_vtable_t diverite_nitekq_device_vtable = { + sizeof(diverite_nitekq_device_t), DC_FAMILY_DIVERITE_NITEKQ, diverite_nitekq_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -156,15 +157,12 @@ diverite_nitekq_device_open (dc_device_t **out, dc_context_t *context, const cha return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (diverite_nitekq_device_t *) malloc (sizeof (diverite_nitekq_device_t)); + device = (diverite_nitekq_device_t *) dc_device_allocate (context, &diverite_nitekq_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &diverite_nitekq_device_vtable); - // Set the default values. device->port = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); @@ -210,7 +208,7 @@ diverite_nitekq_device_open (dc_device_t **out, dc_context_t *context, const cha error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/diverite_nitekq_parser.c b/src/diverite_nitekq_parser.c index a32efa1..460dcbf 100644 --- a/src/diverite_nitekq_parser.c +++ b/src/diverite_nitekq_parser.c @@ -54,6 +54,7 @@ static dc_status_t diverite_nitekq_parser_get_field (dc_parser_t *abstract, dc_f static dc_status_t diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t diverite_nitekq_parser_vtable = { + sizeof(diverite_nitekq_parser_t), DC_FAMILY_DIVERITE_NITEKQ, diverite_nitekq_parser_set_data, /* set_data */ diverite_nitekq_parser_get_datetime, /* datetime */ @@ -66,19 +67,18 @@ static const dc_parser_vtable_t diverite_nitekq_parser_vtable = { dc_status_t diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context) { + diverite_nitekq_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - diverite_nitekq_parser_t *parser = (diverite_nitekq_parser_t *) malloc (sizeof (diverite_nitekq_parser_t)); + parser = (diverite_nitekq_parser_t *) dc_parser_allocate (context, &diverite_nitekq_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &diverite_nitekq_parser_vtable); - // Set the default values. parser->cached = 0; parser->metric = 0; diff --git a/src/divesystem_idive.c b/src/divesystem_idive.c index 9565386..e48e47b 100644 --- a/src/divesystem_idive.c +++ b/src/divesystem_idive.c @@ -77,6 +77,7 @@ static dc_status_t divesystem_idive_device_foreach (dc_device_t *abstract, dc_di static dc_status_t divesystem_idive_device_close (dc_device_t *abstract); static const dc_device_vtable_t divesystem_idive_device_vtable = { + sizeof(divesystem_idive_device_t), DC_FAMILY_DIVESYSTEM_IDIVE, divesystem_idive_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -117,15 +118,12 @@ divesystem_idive_device_open2 (dc_device_t **out, dc_context_t *context, const c return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (divesystem_idive_device_t *) malloc (sizeof (divesystem_idive_device_t)); + device = (divesystem_idive_device_t *) dc_device_allocate (context, &divesystem_idive_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &divesystem_idive_device_vtable); - // Set the default values. device->port = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); @@ -165,7 +163,7 @@ divesystem_idive_device_open2 (dc_device_t **out, dc_context_t *context, const c error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/divesystem_idive_parser.c b/src/divesystem_idive_parser.c index 5ea2052..64454a8 100644 --- a/src/divesystem_idive_parser.c +++ b/src/divesystem_idive_parser.c @@ -64,6 +64,7 @@ static dc_status_t divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_ static dc_status_t divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t divesystem_idive_parser_vtable = { + sizeof(divesystem_idive_parser_t), DC_FAMILY_DIVESYSTEM_IDIVE, divesystem_idive_parser_set_data, /* set_data */ divesystem_idive_parser_get_datetime, /* datetime */ @@ -83,19 +84,18 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context) dc_status_t divesystem_idive_parser_create2 (dc_parser_t **out, dc_context_t *context, unsigned int model) { + divesystem_idive_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - divesystem_idive_parser_t *parser = (divesystem_idive_parser_t *) malloc (sizeof (divesystem_idive_parser_t)); + parser = (divesystem_idive_parser_t *) dc_parser_allocate (context, &divesystem_idive_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - 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; diff --git a/src/hw_frog.c b/src/hw_frog.c index 339c5ef..511052c 100644 --- a/src/hw_frog.c +++ b/src/hw_frog.c @@ -70,6 +70,7 @@ static dc_status_t hw_frog_device_foreach (dc_device_t *abstract, dc_dive_callba static dc_status_t hw_frog_device_close (dc_device_t *abstract); static const dc_device_vtable_t hw_frog_device_vtable = { + sizeof(hw_frog_device_t), DC_FAMILY_HW_FROG, hw_frog_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -209,15 +210,12 @@ hw_frog_device_open (dc_device_t **out, dc_context_t *context, const char *name) return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (hw_frog_device_t *) malloc (sizeof (hw_frog_device_t)); + device = (hw_frog_device_t *) dc_device_allocate (context, &hw_frog_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &hw_frog_device_vtable); - // Set the default values. device->port = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); @@ -263,7 +261,7 @@ hw_frog_device_open (dc_device_t **out, dc_context_t *context, const char *name) error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/hw_ostc.c b/src/hw_ostc.c index d69c3df..6a6c3d7 100644 --- a/src/hw_ostc.c +++ b/src/hw_ostc.c @@ -79,6 +79,7 @@ static dc_status_t hw_ostc_device_foreach (dc_device_t *abstract, dc_dive_callba static dc_status_t hw_ostc_device_close (dc_device_t *abstract); static const dc_device_vtable_t hw_ostc_device_vtable = { + sizeof(hw_ostc_device_t), DC_FAMILY_HW_OSTC, hw_ostc_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -132,15 +133,12 @@ hw_ostc_device_open (dc_device_t **out, dc_context_t *context, const char *name) return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (hw_ostc_device_t *) malloc (sizeof (hw_ostc_device_t)); + device = (hw_ostc_device_t *) dc_device_allocate (context, &hw_ostc_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &hw_ostc_device_vtable); - // Set the default values. device->port = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); @@ -179,7 +177,7 @@ hw_ostc_device_open (dc_device_t **out, dc_context_t *context, const char *name) error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index a2befa0..9b81055 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -123,6 +123,7 @@ static dc_status_t hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callb static dc_status_t hw_ostc3_device_close (dc_device_t *abstract); static const dc_device_vtable_t hw_ostc3_device_vtable = { + sizeof(hw_ostc3_device_t), DC_FAMILY_HW_OSTC3, hw_ostc3_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -282,15 +283,12 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (hw_ostc3_device_t *) malloc (sizeof (hw_ostc3_device_t)); + device = (hw_ostc3_device_t *) dc_device_allocate (context, &hw_ostc3_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &hw_ostc3_device_vtable); - // Set the default values. device->port = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); @@ -331,7 +329,7 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index 5ee2097..abc42ba 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -99,6 +99,7 @@ static dc_status_t hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_typ static dc_status_t hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t hw_ostc_parser_vtable = { + sizeof(hw_ostc_parser_t), DC_FAMILY_HW_OSTC, hw_ostc_parser_set_data, /* set_data */ hw_ostc_parser_get_datetime, /* datetime */ @@ -266,19 +267,18 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) dc_status_t hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int frog) { + hw_ostc_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - hw_ostc_parser_t *parser = (hw_ostc_parser_t *) malloc (sizeof (hw_ostc_parser_t)); + parser = (hw_ostc_parser_t *) dc_parser_allocate (context, &hw_ostc_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &hw_ostc_parser_vtable); - // Set the default values. parser->frog = frog; parser->cached = 0; diff --git a/src/mares_common.c b/src/mares_common.c index 669de99..6f0c3dd 100644 --- a/src/mares_common.c +++ b/src/mares_common.c @@ -52,13 +52,10 @@ #define GAUGE 3 void -mares_common_device_init (mares_common_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable) +mares_common_device_init (mares_common_device_t *device) { assert (device != NULL); - // Initialize the base class. - device_init (&device->base, context, vtable); - // Set the default values. device->port = NULL; device->echo = 0; diff --git a/src/mares_common.h b/src/mares_common.h index 14eeae3..33228c5 100644 --- a/src/mares_common.h +++ b/src/mares_common.h @@ -47,7 +47,7 @@ typedef struct mares_common_device_t { } mares_common_device_t; void -mares_common_device_init (mares_common_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable); +mares_common_device_init (mares_common_device_t *device); dc_status_t mares_common_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); diff --git a/src/mares_darwin.c b/src/mares_darwin.c index d12172f..f8a39d9 100644 --- a/src/mares_darwin.c +++ b/src/mares_darwin.c @@ -63,6 +63,7 @@ static dc_status_t mares_darwin_device_foreach (dc_device_t *abstract, dc_dive_c static dc_status_t mares_darwin_device_close (dc_device_t *abstract); static const dc_device_vtable_t mares_darwin_device_vtable = { + sizeof(mares_darwin_device_t), DC_FAMILY_MARES_DARWIN, mares_darwin_device_set_fingerprint, /* set_fingerprint */ mares_common_device_read, /* read */ @@ -103,14 +104,14 @@ mares_darwin_device_open (dc_device_t **out, dc_context_t *context, const char * return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (mares_darwin_device_t *) malloc (sizeof (mares_darwin_device_t)); + device = (mares_darwin_device_t *) dc_device_allocate (context, &mares_darwin_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } // Initialize the base class. - mares_common_device_init (&device->base, context, &mares_darwin_device_vtable); + mares_common_device_init (&device->base); // Set the default values. memset (device->fingerprint, 0, sizeof (device->fingerprint)); @@ -166,7 +167,7 @@ mares_darwin_device_open (dc_device_t **out, dc_context_t *context, const char * error_close: serial_close (device->base.port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/mares_darwin_parser.c b/src/mares_darwin_parser.c index 67ae51c..42cccb4 100644 --- a/src/mares_darwin_parser.c +++ b/src/mares_darwin_parser.c @@ -49,6 +49,7 @@ static dc_status_t mares_darwin_parser_get_field (dc_parser_t *abstract, dc_fiel static dc_status_t mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t mares_darwin_parser_vtable = { + sizeof(mares_darwin_parser_t), DC_FAMILY_MARES_DARWIN, mares_darwin_parser_set_data, /* set_data */ mares_darwin_parser_get_datetime, /* datetime */ @@ -61,19 +62,18 @@ static const dc_parser_vtable_t mares_darwin_parser_vtable = { dc_status_t mares_darwin_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model) { + mares_darwin_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - mares_darwin_parser_t *parser = (mares_darwin_parser_t *) malloc (sizeof (mares_darwin_parser_t)); + parser = (mares_darwin_parser_t *) dc_parser_allocate (context, &mares_darwin_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &mares_darwin_parser_vtable); - parser->model = model; if (model == DARWINAIR) { diff --git a/src/mares_iconhd.c b/src/mares_iconhd.c index 123b103..79dda55 100644 --- a/src/mares_iconhd.c +++ b/src/mares_iconhd.c @@ -84,6 +84,7 @@ static dc_status_t mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_c static dc_status_t mares_iconhd_device_close (dc_device_t *abstract); static const dc_device_vtable_t mares_iconhd_device_vtable = { + sizeof(mares_iconhd_device_t), DC_FAMILY_MARES_ICONHD, mares_iconhd_device_set_fingerprint, /* set_fingerprint */ mares_iconhd_device_read, /* read */ @@ -221,15 +222,12 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char * return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (mares_iconhd_device_t *) malloc (sizeof (mares_iconhd_device_t)); + device = (mares_iconhd_device_t *) dc_device_allocate (context, &mares_iconhd_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &mares_iconhd_device_vtable); - // Set the default values. device->port = NULL; device->layout = NULL; @@ -316,7 +314,7 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char * error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/mares_iconhd_parser.c b/src/mares_iconhd_parser.c index 728162e..8789a71 100644 --- a/src/mares_iconhd_parser.c +++ b/src/mares_iconhd_parser.c @@ -62,6 +62,7 @@ static dc_status_t mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_fiel static dc_status_t mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t mares_iconhd_parser_vtable = { + sizeof(mares_iconhd_parser_t), DC_FAMILY_MARES_ICONHD, mares_iconhd_parser_set_data, /* set_data */ mares_iconhd_parser_get_datetime, /* datetime */ @@ -197,19 +198,18 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser) dc_status_t mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model) { + mares_iconhd_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - mares_iconhd_parser_t *parser = (mares_iconhd_parser_t *) malloc (sizeof (mares_iconhd_parser_t)); + parser = (mares_iconhd_parser_t *) dc_parser_allocate (context, &mares_iconhd_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &mares_iconhd_parser_vtable); - // Set the default values. parser->model = model; parser->cached = 0; diff --git a/src/mares_nemo.c b/src/mares_nemo.c index e6a1bb8..7f71dbf 100644 --- a/src/mares_nemo.c +++ b/src/mares_nemo.c @@ -61,6 +61,7 @@ static dc_status_t mares_nemo_device_foreach (dc_device_t *abstract, dc_dive_cal static dc_status_t mares_nemo_device_close (dc_device_t *abstract); static const dc_device_vtable_t mares_nemo_device_vtable = { + sizeof(mares_nemo_device_t), DC_FAMILY_MARES_NEMO, mares_nemo_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -97,15 +98,12 @@ mares_nemo_device_open (dc_device_t **out, dc_context_t *context, const char *na return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (mares_nemo_device_t *) malloc (sizeof (mares_nemo_device_t)); + device = (mares_nemo_device_t *) dc_device_allocate (context, &mares_nemo_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &mares_nemo_device_vtable); - // Set the default values. device->port = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); @@ -151,7 +149,7 @@ mares_nemo_device_open (dc_device_t **out, dc_context_t *context, const char *na error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/mares_nemo_parser.c b/src/mares_nemo_parser.c index 487b5f2..33e5916 100644 --- a/src/mares_nemo_parser.c +++ b/src/mares_nemo_parser.c @@ -65,6 +65,7 @@ static dc_status_t mares_nemo_parser_get_field (dc_parser_t *abstract, dc_field_ static dc_status_t mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t mares_nemo_parser_vtable = { + sizeof(mares_nemo_parser_t), DC_FAMILY_MARES_NEMO, mares_nemo_parser_set_data, /* set_data */ mares_nemo_parser_get_datetime, /* datetime */ @@ -77,19 +78,18 @@ static const dc_parser_vtable_t mares_nemo_parser_vtable = { dc_status_t mares_nemo_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model) { + mares_nemo_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - mares_nemo_parser_t *parser = (mares_nemo_parser_t *) malloc (sizeof (mares_nemo_parser_t)); + parser = (mares_nemo_parser_t *) dc_parser_allocate (context, &mares_nemo_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &mares_nemo_parser_vtable); - // Get the freedive mode for this model. unsigned int freedive = FREEDIVE; if (model == NEMOWIDE || model == NEMOAIR || model == PUCK || model == PUCKAIR) diff --git a/src/mares_puck.c b/src/mares_puck.c index 95ba855..67666df 100644 --- a/src/mares_puck.c +++ b/src/mares_puck.c @@ -51,6 +51,7 @@ static dc_status_t mares_puck_device_foreach (dc_device_t *abstract, dc_dive_cal static dc_status_t mares_puck_device_close (dc_device_t *abstract); static const dc_device_vtable_t mares_puck_device_vtable = { + sizeof(mares_puck_device_t), DC_FAMILY_MARES_PUCK, mares_puck_device_set_fingerprint, /* set_fingerprint */ mares_common_device_read, /* read */ @@ -95,14 +96,14 @@ mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *na return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (mares_puck_device_t *) malloc (sizeof (mares_puck_device_t)); + device = (mares_puck_device_t *) dc_device_allocate (context, &mares_puck_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } // Initialize the base class. - mares_common_device_init (&device->base, context, &mares_puck_device_vtable); + mares_common_device_init (&device->base); // Set the default values. device->layout = NULL; @@ -173,7 +174,7 @@ mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *na error_close: serial_close (device->base.port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 93aa5da..d19d82a 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -71,6 +71,7 @@ static dc_status_t oceanic_atom2_device_write (dc_device_t *abstract, unsigned i static dc_status_t oceanic_atom2_device_close (dc_device_t *abstract); static const dc_device_vtable_t oceanic_atom2_device_vtable = { + sizeof(oceanic_atom2_device_t), DC_FAMILY_OCEANIC_ATOM2, oceanic_common_device_set_fingerprint, /* set_fingerprint */ oceanic_atom2_device_read, /* read */ @@ -528,14 +529,14 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (oceanic_atom2_device_t *) malloc (sizeof (oceanic_atom2_device_t)); + device = (oceanic_atom2_device_t *) dc_device_allocate (context, &oceanic_atom2_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } // Initialize the base class. - oceanic_common_device_init (&device->base, context, &oceanic_atom2_device_vtable); + oceanic_common_device_init (&device->base); // Set the default values. device->port = NULL; @@ -643,7 +644,7 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index a6f39ec..54188c2 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -109,6 +109,7 @@ static dc_status_t oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_fie static dc_status_t oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t oceanic_atom2_parser_vtable = { + sizeof(oceanic_atom2_parser_t), DC_FAMILY_OCEANIC_ATOM2, oceanic_atom2_parser_set_data, /* set_data */ oceanic_atom2_parser_get_datetime, /* datetime */ @@ -121,19 +122,18 @@ static const dc_parser_vtable_t oceanic_atom2_parser_vtable = { dc_status_t oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model) { + oceanic_atom2_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - oceanic_atom2_parser_t *parser = (oceanic_atom2_parser_t *) malloc (sizeof (oceanic_atom2_parser_t)); + parser = (oceanic_atom2_parser_t *) dc_parser_allocate (context, &oceanic_atom2_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &oceanic_atom2_parser_vtable); - // Set the default values. parser->model = model; parser->headersize = 9 * PAGESIZE / 2; diff --git a/src/oceanic_common.c b/src/oceanic_common.c index f204309..a1d11fa 100644 --- a/src/oceanic_common.c +++ b/src/oceanic_common.c @@ -125,13 +125,10 @@ oceanic_common_match (const unsigned char *version, const oceanic_common_version void -oceanic_common_device_init (oceanic_common_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable) +oceanic_common_device_init (oceanic_common_device_t *device) { assert (device != NULL); - // Initialize the base class. - device_init (&device->base, context, vtable); - // Set the default values. memset (device->version, 0, sizeof (device->version)); memset (device->fingerprint, 0, sizeof (device->fingerprint)); diff --git a/src/oceanic_common.h b/src/oceanic_common.h index a9286aa..e5e53f0 100644 --- a/src/oceanic_common.h +++ b/src/oceanic_common.h @@ -71,7 +71,7 @@ int oceanic_common_match (const unsigned char *version, const oceanic_common_version_t patterns[], unsigned int n); void -oceanic_common_device_init (oceanic_common_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable); +oceanic_common_device_init (oceanic_common_device_t *device); dc_status_t oceanic_common_device_set_fingerprint (dc_device_t *device, const unsigned char data[], unsigned int size); diff --git a/src/oceanic_veo250.c b/src/oceanic_veo250.c index 15d8070..653d51e 100644 --- a/src/oceanic_veo250.c +++ b/src/oceanic_veo250.c @@ -54,6 +54,7 @@ static dc_status_t oceanic_veo250_device_read (dc_device_t *abstract, unsigned i static dc_status_t oceanic_veo250_device_close (dc_device_t *abstract); static const dc_device_vtable_t oceanic_veo250_device_vtable = { + sizeof(oceanic_veo250_device_t), DC_FAMILY_OCEANIC_VEO250, oceanic_common_device_set_fingerprint, /* set_fingerprint */ oceanic_veo250_device_read, /* read */ @@ -228,14 +229,14 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (oceanic_veo250_device_t *) malloc (sizeof (oceanic_veo250_device_t)); + device = (oceanic_veo250_device_t *) dc_device_allocate (context, &oceanic_veo250_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } // Initialize the base class. - oceanic_common_device_init (&device->base, context, &oceanic_veo250_device_vtable); + oceanic_common_device_init (&device->base); // Override the base class values. device->base.layout = &oceanic_veo250_layout; @@ -306,7 +307,7 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/oceanic_veo250_parser.c b/src/oceanic_veo250_parser.c index 4cc8ebe..a300af8 100644 --- a/src/oceanic_veo250_parser.c +++ b/src/oceanic_veo250_parser.c @@ -53,6 +53,7 @@ static dc_status_t oceanic_veo250_parser_get_field (dc_parser_t *abstract, dc_fi static dc_status_t oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t oceanic_veo250_parser_vtable = { + sizeof(oceanic_veo250_parser_t), DC_FAMILY_OCEANIC_VEO250, oceanic_veo250_parser_set_data, /* set_data */ oceanic_veo250_parser_get_datetime, /* datetime */ @@ -65,19 +66,18 @@ static const dc_parser_vtable_t oceanic_veo250_parser_vtable = { dc_status_t oceanic_veo250_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model) { + oceanic_veo250_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - oceanic_veo250_parser_t *parser = (oceanic_veo250_parser_t *) malloc (sizeof (oceanic_veo250_parser_t)); + parser = (oceanic_veo250_parser_t *) dc_parser_allocate (context, &oceanic_veo250_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &oceanic_veo250_parser_vtable); - // Set the default values. parser->model = model; parser->cached = 0; diff --git a/src/oceanic_vtpro.c b/src/oceanic_vtpro.c index 67867b7..040f23f 100644 --- a/src/oceanic_vtpro.c +++ b/src/oceanic_vtpro.c @@ -54,6 +54,7 @@ static dc_status_t oceanic_vtpro_device_read (dc_device_t *abstract, unsigned in static dc_status_t oceanic_vtpro_device_close (dc_device_t *abstract); static const dc_device_vtable_t oceanic_vtpro_device_vtable = { + sizeof(oceanic_vtpro_device_t), DC_FAMILY_OCEANIC_VTPRO, oceanic_common_device_set_fingerprint, /* set_fingerprint */ oceanic_vtpro_device_read, /* read */ @@ -261,14 +262,14 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (oceanic_vtpro_device_t *) malloc (sizeof (oceanic_vtpro_device_t)); + device = (oceanic_vtpro_device_t *) dc_device_allocate (context, &oceanic_vtpro_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } // Initialize the base class. - oceanic_common_device_init (&device->base, context, &oceanic_vtpro_device_vtable); + oceanic_common_device_init (&device->base); // Override the base class values. device->base.multipage = MULTIPAGE; @@ -349,7 +350,7 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/oceanic_vtpro_parser.c b/src/oceanic_vtpro_parser.c index c1b5150..d2d7919 100644 --- a/src/oceanic_vtpro_parser.c +++ b/src/oceanic_vtpro_parser.c @@ -47,6 +47,7 @@ static dc_status_t oceanic_vtpro_parser_get_field (dc_parser_t *abstract, dc_fie static dc_status_t oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t oceanic_vtpro_parser_vtable = { + sizeof(oceanic_vtpro_parser_t), DC_FAMILY_OCEANIC_VTPRO, oceanic_vtpro_parser_set_data, /* set_data */ oceanic_vtpro_parser_get_datetime, /* datetime */ @@ -59,19 +60,18 @@ static const dc_parser_vtable_t oceanic_vtpro_parser_vtable = { dc_status_t oceanic_vtpro_parser_create (dc_parser_t **out, dc_context_t *context) { + oceanic_vtpro_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - oceanic_vtpro_parser_t *parser = (oceanic_vtpro_parser_t *) malloc (sizeof (oceanic_vtpro_parser_t)); + parser = (oceanic_vtpro_parser_t *) dc_parser_allocate (context, &oceanic_vtpro_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &oceanic_vtpro_parser_vtable); - // Set the default values. parser->cached = 0; parser->divetime = 0; diff --git a/src/parser-private.h b/src/parser-private.h index 63f0f4f..eed9d51 100644 --- a/src/parser-private.h +++ b/src/parser-private.h @@ -42,6 +42,8 @@ struct dc_parser_t { }; struct dc_parser_vtable_t { + size_t size; + dc_family_t type; dc_status_t (*set_data) (dc_parser_t *parser, const unsigned char *data, unsigned int size); @@ -55,8 +57,11 @@ struct dc_parser_vtable_t { dc_status_t (*destroy) (dc_parser_t *parser); }; +dc_parser_t * +dc_parser_allocate (dc_context_t *context, const dc_parser_vtable_t *vtable); + void -parser_init (dc_parser_t *parser, dc_context_t *context, const dc_parser_vtable_t *vtable); +dc_parser_deallocate (dc_parser_t *parser); int dc_parser_isinstance (dc_parser_t *parser, const dc_parser_vtable_t *vtable); diff --git a/src/parser.c b/src/parser.c index bc6b406..5fb790f 100644 --- a/src/parser.c +++ b/src/parser.c @@ -20,6 +20,7 @@ */ #include +#include #include #include @@ -35,6 +36,7 @@ #include #include +#include "context-private.h" #include "parser-private.h" #include "device-private.h" @@ -152,15 +154,35 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device) } -void -parser_init (dc_parser_t *parser, dc_context_t *context, const dc_parser_vtable_t *vtable) +dc_parser_t * +dc_parser_allocate (dc_context_t *context, const dc_parser_vtable_t *vtable) { + dc_parser_t *parser = NULL; + + assert(vtable != NULL); + assert(vtable->size >= sizeof(dc_parser_t)); + + // Allocate memory. + parser = (dc_parser_t *) malloc (vtable->size); + if (parser == NULL) { + ERROR (context, "Failed to allocate memory."); + return parser; + } + + // Initialize the base class. parser->vtable = vtable; parser->context = context; parser->data = NULL; parser->size = 0; + + return parser; } +void +dc_parser_deallocate (dc_parser_t *parser) +{ + free (parser); +} int dc_parser_isinstance (dc_parser_t *parser, const dc_parser_vtable_t *vtable) @@ -248,7 +270,7 @@ dc_parser_destroy (dc_parser_t *parser) status = parser->vtable->destroy (parser); } - free (parser); + dc_parser_deallocate (parser); return status; } diff --git a/src/reefnet_sensus.c b/src/reefnet_sensus.c index ba40ee5..0660155 100644 --- a/src/reefnet_sensus.c +++ b/src/reefnet_sensus.c @@ -56,6 +56,7 @@ static dc_status_t reefnet_sensus_device_foreach (dc_device_t *abstract, dc_dive static dc_status_t reefnet_sensus_device_close (dc_device_t *abstract); static const dc_device_vtable_t reefnet_sensus_device_vtable = { + sizeof(reefnet_sensus_device_t), DC_FAMILY_REEFNET_SENSUS, reefnet_sensus_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -96,15 +97,12 @@ reefnet_sensus_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (reefnet_sensus_device_t *) malloc (sizeof (reefnet_sensus_device_t)); + device = (reefnet_sensus_device_t *) dc_device_allocate (context, &reefnet_sensus_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &reefnet_sensus_device_vtable); - // Set the default values. device->port = NULL; device->waiting = 0; @@ -146,7 +144,7 @@ reefnet_sensus_device_open (dc_device_t **out, dc_context_t *context, const char error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/reefnet_sensus_parser.c b/src/reefnet_sensus_parser.c index b5702f2..ba4b7de 100644 --- a/src/reefnet_sensus_parser.c +++ b/src/reefnet_sensus_parser.c @@ -54,6 +54,7 @@ static dc_status_t reefnet_sensus_parser_get_field (dc_parser_t *abstract, dc_fi static dc_status_t reefnet_sensus_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t reefnet_sensus_parser_vtable = { + sizeof(reefnet_sensus_parser_t), DC_FAMILY_REEFNET_SENSUS, reefnet_sensus_parser_set_data, /* set_data */ reefnet_sensus_parser_get_datetime, /* datetime */ @@ -66,19 +67,18 @@ static const dc_parser_vtable_t reefnet_sensus_parser_vtable = { dc_status_t reefnet_sensus_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int devtime, dc_ticks_t systime) { + reefnet_sensus_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - reefnet_sensus_parser_t *parser = (reefnet_sensus_parser_t *) malloc (sizeof (reefnet_sensus_parser_t)); + parser = (reefnet_sensus_parser_t *) dc_parser_allocate (context, &reefnet_sensus_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &reefnet_sensus_parser_vtable); - // Set the default values. parser->atmospheric = ATM; parser->hydrostatic = 1025.0 * GRAVITY; diff --git a/src/reefnet_sensuspro.c b/src/reefnet_sensuspro.c index 1063166..8e17f1e 100644 --- a/src/reefnet_sensuspro.c +++ b/src/reefnet_sensuspro.c @@ -55,6 +55,7 @@ static dc_status_t reefnet_sensuspro_device_foreach (dc_device_t *abstract, dc_d static dc_status_t reefnet_sensuspro_device_close (dc_device_t *abstract); static const dc_device_vtable_t reefnet_sensuspro_device_vtable = { + sizeof(reefnet_sensuspro_device_t), DC_FAMILY_REEFNET_SENSUSPRO, reefnet_sensuspro_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -75,15 +76,12 @@ reefnet_sensuspro_device_open (dc_device_t **out, dc_context_t *context, const c return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (reefnet_sensuspro_device_t *) malloc (sizeof (reefnet_sensuspro_device_t)); + device = (reefnet_sensuspro_device_t *) dc_device_allocate (context, &reefnet_sensuspro_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &reefnet_sensuspro_device_vtable); - // Set the default values. device->port = NULL; device->timestamp = 0; @@ -124,7 +122,7 @@ reefnet_sensuspro_device_open (dc_device_t **out, dc_context_t *context, const c error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/reefnet_sensuspro_parser.c b/src/reefnet_sensuspro_parser.c index cc9d999..70decf8 100644 --- a/src/reefnet_sensuspro_parser.c +++ b/src/reefnet_sensuspro_parser.c @@ -53,6 +53,7 @@ static dc_status_t reefnet_sensuspro_parser_get_field (dc_parser_t *abstract, dc static dc_status_t reefnet_sensuspro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t reefnet_sensuspro_parser_vtable = { + sizeof(reefnet_sensuspro_parser_t), DC_FAMILY_REEFNET_SENSUSPRO, reefnet_sensuspro_parser_set_data, /* set_data */ reefnet_sensuspro_parser_get_datetime, /* datetime */ @@ -65,19 +66,18 @@ static const dc_parser_vtable_t reefnet_sensuspro_parser_vtable = { dc_status_t reefnet_sensuspro_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int devtime, dc_ticks_t systime) { + reefnet_sensuspro_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - reefnet_sensuspro_parser_t *parser = (reefnet_sensuspro_parser_t *) malloc (sizeof (reefnet_sensuspro_parser_t)); + parser = (reefnet_sensuspro_parser_t *) dc_parser_allocate (context, &reefnet_sensuspro_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &reefnet_sensuspro_parser_vtable); - // Set the default values. parser->atmospheric = ATM; parser->hydrostatic = 1025.0 * GRAVITY; diff --git a/src/reefnet_sensusultra.c b/src/reefnet_sensusultra.c index d246c14..db070e6 100644 --- a/src/reefnet_sensusultra.c +++ b/src/reefnet_sensusultra.c @@ -64,6 +64,7 @@ static dc_status_t reefnet_sensusultra_device_foreach (dc_device_t *abstract, dc static dc_status_t reefnet_sensusultra_device_close (dc_device_t *abstract); static const dc_device_vtable_t reefnet_sensusultra_device_vtable = { + sizeof(reefnet_sensusultra_device_t), DC_FAMILY_REEFNET_SENSUSULTRA, reefnet_sensusultra_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -84,15 +85,12 @@ reefnet_sensusultra_device_open (dc_device_t **out, dc_context_t *context, const return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (reefnet_sensusultra_device_t *) malloc (sizeof (reefnet_sensusultra_device_t)); + device = (reefnet_sensusultra_device_t *) dc_device_allocate (context, &reefnet_sensusultra_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &reefnet_sensusultra_device_vtable); - // Set the default values. device->port = NULL; device->timestamp = 0; @@ -133,7 +131,7 @@ reefnet_sensusultra_device_open (dc_device_t **out, dc_context_t *context, const error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/reefnet_sensusultra_parser.c b/src/reefnet_sensusultra_parser.c index 339fa0d..d44edfe 100644 --- a/src/reefnet_sensusultra_parser.c +++ b/src/reefnet_sensusultra_parser.c @@ -53,6 +53,7 @@ static dc_status_t reefnet_sensusultra_parser_get_field (dc_parser_t *abstract, static dc_status_t reefnet_sensusultra_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t reefnet_sensusultra_parser_vtable = { + sizeof(reefnet_sensusultra_parser_t), DC_FAMILY_REEFNET_SENSUSULTRA, reefnet_sensusultra_parser_set_data, /* set_data */ reefnet_sensusultra_parser_get_datetime, /* datetime */ @@ -65,19 +66,18 @@ static const dc_parser_vtable_t reefnet_sensusultra_parser_vtable = { dc_status_t reefnet_sensusultra_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int devtime, dc_ticks_t systime) { + reefnet_sensusultra_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - reefnet_sensusultra_parser_t *parser = (reefnet_sensusultra_parser_t *) malloc (sizeof (reefnet_sensusultra_parser_t)); + parser = (reefnet_sensusultra_parser_t *) dc_parser_allocate (context, &reefnet_sensusultra_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &reefnet_sensusultra_parser_vtable); - // Set the default values. parser->atmospheric = ATM; parser->hydrostatic = 1025.0 * GRAVITY; diff --git a/src/shearwater_petrel.c b/src/shearwater_petrel.c index f5e6d76..b791388 100644 --- a/src/shearwater_petrel.c +++ b/src/shearwater_petrel.c @@ -51,6 +51,7 @@ static dc_status_t shearwater_petrel_device_foreach (dc_device_t *abstract, dc_d static dc_status_t shearwater_petrel_device_close (dc_device_t *abstract); static const dc_device_vtable_t shearwater_petrel_device_vtable = { + sizeof(shearwater_petrel_device_t), DC_FAMILY_SHEARWATER_PETREL, shearwater_petrel_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -86,15 +87,12 @@ shearwater_petrel_device_open (dc_device_t **out, dc_context_t *context, const c return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (shearwater_petrel_device_t *) malloc (sizeof (shearwater_petrel_device_t)); + device = (shearwater_petrel_device_t *) dc_device_allocate (context, &shearwater_petrel_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base.base, context, &shearwater_petrel_device_vtable); - // Set the default values. memset (device->fingerprint, 0, sizeof (device->fingerprint)); @@ -109,7 +107,7 @@ shearwater_petrel_device_open (dc_device_t **out, dc_context_t *context, const c return DC_STATUS_SUCCESS; error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/shearwater_predator.c b/src/shearwater_predator.c index f5cfbc6..7975b8f 100644 --- a/src/shearwater_predator.c +++ b/src/shearwater_predator.c @@ -52,6 +52,7 @@ static dc_status_t shearwater_predator_device_foreach (dc_device_t *abstract, dc static dc_status_t shearwater_predator_device_close (dc_device_t *abstract); static const dc_device_vtable_t shearwater_predator_device_vtable = { + sizeof(shearwater_predator_device_t), DC_FAMILY_SHEARWATER_PREDATOR, shearwater_predator_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -72,15 +73,12 @@ shearwater_predator_device_open (dc_device_t **out, dc_context_t *context, const return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (shearwater_predator_device_t *) malloc (sizeof (shearwater_predator_device_t)); + device = (shearwater_predator_device_t *) dc_device_allocate (context, &shearwater_predator_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base.base, context, &shearwater_predator_device_vtable); - // Set the default values. memset (device->fingerprint, 0, sizeof (device->fingerprint)); @@ -95,7 +93,7 @@ shearwater_predator_device_open (dc_device_t **out, dc_context_t *context, const return DC_STATUS_SUCCESS; error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index cacdcca..f1a5c31 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -69,6 +69,7 @@ static dc_status_t shearwater_predator_parser_get_field (dc_parser_t *abstract, static dc_status_t shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t shearwater_predator_parser_vtable = { + sizeof(shearwater_predator_parser_t), DC_FAMILY_SHEARWATER_PREDATOR, shearwater_predator_parser_set_data, /* set_data */ shearwater_predator_parser_get_datetime, /* datetime */ @@ -78,6 +79,7 @@ static const dc_parser_vtable_t shearwater_predator_parser_vtable = { }; static const dc_parser_vtable_t shearwater_petrel_parser_vtable = { + sizeof(shearwater_predator_parser_t), DC_FAMILY_SHEARWATER_PETREL, shearwater_predator_parser_set_data, /* set_data */ shearwater_predator_parser_get_datetime, /* datetime */ @@ -104,27 +106,31 @@ shearwater_predator_find_gasmix (shearwater_predator_parser_t *parser, unsigned dc_status_t shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int petrel) { + shearwater_predator_parser_t *parser = NULL; + const dc_parser_vtable_t *vtable = NULL; + unsigned int samplesize = 0; + if (out == NULL) return DC_STATUS_INVALIDARGS; + if (petrel) { + vtable = &shearwater_petrel_parser_vtable; + samplesize = SZ_SAMPLE_PETREL; + } else { + vtable = &shearwater_predator_parser_vtable; + samplesize = SZ_SAMPLE_PREDATOR; + } + // Allocate memory. - shearwater_predator_parser_t *parser = (shearwater_predator_parser_t *) malloc (sizeof (shearwater_predator_parser_t)); + parser = (shearwater_predator_parser_t *) dc_parser_allocate (context, vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser->petrel = petrel; - if (petrel) { - parser_init (&parser->base, context, &shearwater_petrel_parser_vtable); - parser->samplesize = SZ_SAMPLE_PETREL; - } else { - parser_init (&parser->base, context, &shearwater_predator_parser_vtable); - parser->samplesize = SZ_SAMPLE_PREDATOR; - } - // Set the default values. + parser->petrel = petrel; + parser->samplesize = samplesize; parser->cached = 0; parser->headersize = 0; parser->footersize = 0; diff --git a/src/suunto_common.c b/src/suunto_common.c index 44c5299..9988b86 100644 --- a/src/suunto_common.c +++ b/src/suunto_common.c @@ -31,13 +31,10 @@ #define RB_PROFILE_PEEK(a,l) ringbuffer_decrement (a, l->peek, l->rb_profile_begin, l->rb_profile_end) void -suunto_common_device_init (suunto_common_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable) +suunto_common_device_init (suunto_common_device_t *device) { assert (device != NULL); - // Initialize the base class. - device_init (&device->base, context, vtable); - // Set the default values. memset (device->fingerprint, 0, sizeof (device->fingerprint)); } diff --git a/src/suunto_common.h b/src/suunto_common.h index 151fe45..49fb29f 100644 --- a/src/suunto_common.h +++ b/src/suunto_common.h @@ -46,7 +46,7 @@ typedef struct suunto_common_layout_t { } suunto_common_layout_t; void -suunto_common_device_init (suunto_common_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable); +suunto_common_device_init (suunto_common_device_t *device); dc_status_t suunto_common_device_set_fingerprint (dc_device_t *device, const unsigned char data[], unsigned int size); diff --git a/src/suunto_common2.c b/src/suunto_common2.c index 2149612..2abe386 100644 --- a/src/suunto_common2.c +++ b/src/suunto_common2.c @@ -40,13 +40,10 @@ #define VTABLE(abstract) ((suunto_common2_device_vtable_t *) abstract->vtable) void -suunto_common2_device_init (suunto_common2_device_t *device, dc_context_t *context, const suunto_common2_device_vtable_t *vtable) +suunto_common2_device_init (suunto_common2_device_t *device) { assert (device != NULL); - // Initialize the base class. - device_init (&device->base, context, &vtable->base); - // Set the default values. device->layout = NULL; memset (device->version, 0, sizeof (device->version)); diff --git a/src/suunto_common2.h b/src/suunto_common2.h index bbcf72b..5eff8d2 100644 --- a/src/suunto_common2.h +++ b/src/suunto_common2.h @@ -53,7 +53,7 @@ typedef struct suunto_common2_device_vtable_t { } suunto_common2_device_vtable_t; void -suunto_common2_device_init (suunto_common2_device_t *device, dc_context_t *context, const suunto_common2_device_vtable_t *vtable); +suunto_common2_device_init (suunto_common2_device_t *device); dc_status_t suunto_common2_device_set_fingerprint (dc_device_t *device, const unsigned char data[], unsigned int size); diff --git a/src/suunto_d9.c b/src/suunto_d9.c index ce3ff89..0d51540 100644 --- a/src/suunto_d9.c +++ b/src/suunto_d9.c @@ -55,6 +55,7 @@ static dc_status_t suunto_d9_device_close (dc_device_t *abstract); static const suunto_common2_device_vtable_t suunto_d9_device_vtable = { { + sizeof(suunto_d9_device_t), DC_FAMILY_SUUNTO_D9, suunto_common2_device_set_fingerprint, /* set_fingerprint */ suunto_common2_device_read, /* read */ @@ -136,14 +137,14 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (suunto_d9_device_t *) malloc (sizeof (suunto_d9_device_t)); + device = (suunto_d9_device_t *) dc_device_allocate (context, &suunto_d9_device_vtable.base); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } // Initialize the base class. - suunto_common2_device_init (&device->base, context, &suunto_d9_device_vtable); + suunto_common2_device_init (&device->base); // Set the default values. device->port = NULL; @@ -207,7 +208,7 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c index adda93b..4b312d4 100644 --- a/src/suunto_d9_parser.c +++ b/src/suunto_d9_parser.c @@ -85,6 +85,7 @@ static dc_status_t suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_t static dc_status_t suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t suunto_d9_parser_vtable = { + sizeof(suunto_d9_parser_t), DC_FAMILY_SUUNTO_D9, suunto_d9_parser_set_data, /* set_data */ suunto_d9_parser_get_datetime, /* datetime */ @@ -202,19 +203,18 @@ suunto_d9_parser_cache (suunto_d9_parser_t *parser) dc_status_t suunto_d9_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model) { + suunto_d9_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - suunto_d9_parser_t *parser = (suunto_d9_parser_t *) malloc (sizeof (suunto_d9_parser_t)); + parser = (suunto_d9_parser_t *) dc_parser_allocate (context, &suunto_d9_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &suunto_d9_parser_vtable); - // Set the default values. parser->model = model; parser->cached = 0; diff --git a/src/suunto_eon.c b/src/suunto_eon.c index 306dac5..6e8375c 100644 --- a/src/suunto_eon.c +++ b/src/suunto_eon.c @@ -50,6 +50,7 @@ static dc_status_t suunto_eon_device_foreach (dc_device_t *abstract, dc_dive_cal static dc_status_t suunto_eon_device_close (dc_device_t *abstract); static const dc_device_vtable_t suunto_eon_device_vtable = { + sizeof(suunto_eon_device_t), DC_FAMILY_SUUNTO_EON, suunto_common_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -78,14 +79,14 @@ suunto_eon_device_open (dc_device_t **out, dc_context_t *context, const char *na return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (suunto_eon_device_t *) malloc (sizeof (suunto_eon_device_t)); + device = (suunto_eon_device_t *) dc_device_allocate (context, &suunto_eon_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } // Initialize the base class. - suunto_common_device_init (&device->base, context, &suunto_eon_device_vtable); + suunto_common_device_init (&device->base); // Set the default values. device->port = NULL; @@ -127,7 +128,7 @@ suunto_eon_device_open (dc_device_t **out, dc_context_t *context, const char *na error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/suunto_eon_parser.c b/src/suunto_eon_parser.c index be38d7f..70fa74f 100644 --- a/src/suunto_eon_parser.c +++ b/src/suunto_eon_parser.c @@ -49,6 +49,7 @@ static dc_status_t suunto_eon_parser_get_field (dc_parser_t *abstract, dc_field_ static dc_status_t suunto_eon_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t suunto_eon_parser_vtable = { + sizeof(suunto_eon_parser_t), DC_FAMILY_SUUNTO_EON, suunto_eon_parser_set_data, /* set_data */ suunto_eon_parser_get_datetime, /* datetime */ @@ -110,19 +111,18 @@ suunto_eon_parser_cache (suunto_eon_parser_t *parser) dc_status_t suunto_eon_parser_create (dc_parser_t **out, dc_context_t *context, int spyder) { + suunto_eon_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - suunto_eon_parser_t *parser = (suunto_eon_parser_t *) malloc (sizeof (suunto_eon_parser_t)); + parser = (suunto_eon_parser_t *) dc_parser_allocate (context, &suunto_eon_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &suunto_eon_parser_vtable); - // Set the default values. parser->spyder = spyder; parser->cached = 0; diff --git a/src/suunto_eonsteel.c b/src/suunto_eonsteel.c index 03b6f99..ec7cfe3 100644 --- a/src/suunto_eonsteel.c +++ b/src/suunto_eonsteel.c @@ -85,6 +85,7 @@ static dc_status_t suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive 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 */ NULL, /* read */ @@ -557,12 +558,12 @@ dc_status_t suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, const char *name, unsigned int model) { dc_status_t status = DC_STATUS_SUCCESS; - suunto_eonsteel_device_t *eon; + suunto_eonsteel_device_t *eon = NULL; if (out == NULL) return DC_STATUS_INVALIDARGS; - eon = (suunto_eonsteel_device_t *) calloc(1, sizeof(suunto_eonsteel_device_t)); + eon = (suunto_eonsteel_device_t *) dc_device_allocate(context, &suunto_eonsteel_device_vtable); if (!eon) return DC_STATUS_NOMEMORY; @@ -570,9 +571,6 @@ suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, const char eon->magic = INIT_MAGIC; eon->seq = INIT_SEQ; - // Set up the libdivecomputer interfaces - device_init(&eon->base, context, &suunto_eonsteel_device_vtable); - if (libusb_init(&eon->ctx)) { ERROR(context, "libusb_init() failed"); status = DC_STATUS_IO; diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index e638bde..19fbf99 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -1196,6 +1196,7 @@ suunto_eonsteel_parser_destroy(dc_parser_t *parser) } static const dc_parser_vtable_t suunto_eonsteel_parser_vtable = { + sizeof(suunto_eonsteel_parser_t), DC_FAMILY_SUUNTO_EONSTEEL, suunto_eonsteel_parser_set_data, /* set_data */ suunto_eonsteel_parser_get_datetime, /* datetime */ @@ -1207,18 +1208,21 @@ static const dc_parser_vtable_t suunto_eonsteel_parser_vtable = { dc_status_t suunto_eonsteel_parser_create(dc_parser_t **out, dc_context_t *context, unsigned int model) { - suunto_eonsteel_parser_t *eon; + suunto_eonsteel_parser_t *parser = NULL; if (out == NULL) return DC_STATUS_INVALIDARGS; - eon = (suunto_eonsteel_parser_t *) calloc(1, sizeof(*eon)); - if (!eon) + parser = (suunto_eonsteel_parser_t *) dc_parser_allocate (context, &suunto_eonsteel_parser_vtable); + if (parser == NULL) { + ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; + } - parser_init(&eon->base, context, &suunto_eonsteel_parser_vtable); + memset(&parser->type_desc, 0, sizeof(parser->type_desc)); + memset(&parser->cache, 0, sizeof(parser->cache)); - *out = (dc_parser_t *) eon; + *out = (dc_parser_t *) parser; return DC_STATUS_SUCCESS; } diff --git a/src/suunto_solution.c b/src/suunto_solution.c index 3ff1f60..d151352 100644 --- a/src/suunto_solution.c +++ b/src/suunto_solution.c @@ -52,6 +52,7 @@ static dc_status_t suunto_solution_device_foreach (dc_device_t *abstract, dc_div static dc_status_t suunto_solution_device_close (dc_device_t *abstract); static const dc_device_vtable_t suunto_solution_device_vtable = { + sizeof(suunto_solution_device_t), DC_FAMILY_SUUNTO_SOLUTION, NULL, /* set_fingerprint */ NULL, /* read */ @@ -72,15 +73,12 @@ suunto_solution_device_open (dc_device_t **out, dc_context_t *context, const cha return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (suunto_solution_device_t *) malloc (sizeof (suunto_solution_device_t)); + device = (suunto_solution_device_t *) dc_device_allocate (context, &suunto_solution_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &suunto_solution_device_vtable); - // Set the default values. device->port = NULL; @@ -121,7 +119,7 @@ suunto_solution_device_open (dc_device_t **out, dc_context_t *context, const cha error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/suunto_solution_parser.c b/src/suunto_solution_parser.c index 8a6ad62..8372457 100644 --- a/src/suunto_solution_parser.c +++ b/src/suunto_solution_parser.c @@ -44,6 +44,7 @@ static dc_status_t suunto_solution_parser_get_field (dc_parser_t *abstract, dc_f static dc_status_t suunto_solution_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t suunto_solution_parser_vtable = { + sizeof(suunto_solution_parser_t), DC_FAMILY_SUUNTO_SOLUTION, suunto_solution_parser_set_data, /* set_data */ NULL, /* datetime */ @@ -56,19 +57,18 @@ static const dc_parser_vtable_t suunto_solution_parser_vtable = { dc_status_t suunto_solution_parser_create (dc_parser_t **out, dc_context_t *context) { + suunto_solution_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - suunto_solution_parser_t *parser = (suunto_solution_parser_t *) malloc (sizeof (suunto_solution_parser_t)); + parser = (suunto_solution_parser_t *) dc_parser_allocate (context, &suunto_solution_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &suunto_solution_parser_vtable); - // Set the default values. parser->cached = 0; parser->divetime = 0; diff --git a/src/suunto_vyper.c b/src/suunto_vyper.c index 701fbeb..8ec502f 100644 --- a/src/suunto_vyper.c +++ b/src/suunto_vyper.c @@ -62,6 +62,7 @@ static dc_status_t suunto_vyper_device_foreach (dc_device_t *abstract, dc_dive_c static dc_status_t suunto_vyper_device_close (dc_device_t *abstract); static const dc_device_vtable_t suunto_vyper_device_vtable = { + sizeof(suunto_vyper_device_t), DC_FAMILY_SUUNTO_VYPER, suunto_common_device_set_fingerprint, /* set_fingerprint */ suunto_vyper_device_read, /* read */ @@ -98,14 +99,14 @@ suunto_vyper_device_open (dc_device_t **out, dc_context_t *context, const char * return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (suunto_vyper_device_t *) malloc (sizeof (suunto_vyper_device_t)); + device = (suunto_vyper_device_t *) dc_device_allocate (context, &suunto_vyper_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } // Initialize the base class. - suunto_common_device_init (&device->base, context, &suunto_vyper_device_vtable); + suunto_common_device_init (&device->base); // Set the default values. device->port = NULL; @@ -153,7 +154,7 @@ suunto_vyper_device_open (dc_device_t **out, dc_context_t *context, const char * error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/suunto_vyper2.c b/src/suunto_vyper2.c index e701164..a0b07a4 100644 --- a/src/suunto_vyper2.c +++ b/src/suunto_vyper2.c @@ -49,6 +49,7 @@ static dc_status_t suunto_vyper2_device_close (dc_device_t *abstract); static const suunto_common2_device_vtable_t suunto_vyper2_device_vtable = { { + sizeof(suunto_vyper2_device_t), DC_FAMILY_SUUNTO_VYPER2, suunto_common2_device_set_fingerprint, /* set_fingerprint */ suunto_common2_device_read, /* read */ @@ -87,14 +88,14 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (suunto_vyper2_device_t *) malloc (sizeof (suunto_vyper2_device_t)); + device = (suunto_vyper2_device_t *) dc_device_allocate (context, &suunto_vyper2_device_vtable.base); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } // Initialize the base class. - suunto_common2_device_init (&device->base, context, &suunto_vyper2_device_vtable); + suunto_common2_device_init (&device->base); // Set the default values. device->port = NULL; @@ -159,7 +160,7 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/suunto_vyper_parser.c b/src/suunto_vyper_parser.c index 4628cb1..7eee580 100644 --- a/src/suunto_vyper_parser.c +++ b/src/suunto_vyper_parser.c @@ -50,6 +50,7 @@ static dc_status_t suunto_vyper_parser_get_field (dc_parser_t *abstract, dc_fiel static dc_status_t suunto_vyper_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t suunto_vyper_parser_vtable = { + sizeof(suunto_vyper_parser_t), DC_FAMILY_SUUNTO_VYPER, suunto_vyper_parser_set_data, /* set_data */ suunto_vyper_parser_get_datetime, /* datetime */ @@ -160,19 +161,18 @@ suunto_vyper_parser_cache (suunto_vyper_parser_t *parser) dc_status_t suunto_vyper_parser_create (dc_parser_t **out, dc_context_t *context) { + suunto_vyper_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - suunto_vyper_parser_t *parser = (suunto_vyper_parser_t *) malloc (sizeof (suunto_vyper_parser_t)); + parser = (suunto_vyper_parser_t *) dc_parser_allocate (context, &suunto_vyper_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &suunto_vyper_parser_vtable); - // Set the default values. parser->cached = 0; parser->divetime = 0; diff --git a/src/uwatec_aladin.c b/src/uwatec_aladin.c index 7cd7dff..47c0ee2 100644 --- a/src/uwatec_aladin.c +++ b/src/uwatec_aladin.c @@ -61,6 +61,7 @@ static dc_status_t uwatec_aladin_device_foreach (dc_device_t *abstract, dc_dive_ static dc_status_t uwatec_aladin_device_close (dc_device_t *abstract); static const dc_device_vtable_t uwatec_aladin_device_vtable = { + sizeof(uwatec_aladin_device_t), DC_FAMILY_UWATEC_ALADIN, uwatec_aladin_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -81,15 +82,12 @@ uwatec_aladin_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (uwatec_aladin_device_t *) malloc (sizeof (uwatec_aladin_device_t)); + device = (uwatec_aladin_device_t *) dc_device_allocate (context, &uwatec_aladin_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &uwatec_aladin_device_vtable); - // Set the default values. device->port = NULL; device->timestamp = 0; @@ -134,7 +132,7 @@ uwatec_aladin_device_open (dc_device_t **out, dc_context_t *context, const char error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/uwatec_memomouse.c b/src/uwatec_memomouse.c index 29b2c69..ba1153a 100644 --- a/src/uwatec_memomouse.c +++ b/src/uwatec_memomouse.c @@ -57,6 +57,7 @@ static dc_status_t uwatec_memomouse_device_foreach (dc_device_t *abstract, dc_di static dc_status_t uwatec_memomouse_device_close (dc_device_t *abstract); static const dc_device_vtable_t uwatec_memomouse_device_vtable = { + sizeof(uwatec_memomouse_device_t), DC_FAMILY_UWATEC_MEMOMOUSE, uwatec_memomouse_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -77,15 +78,12 @@ uwatec_memomouse_device_open (dc_device_t **out, dc_context_t *context, const ch return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (uwatec_memomouse_device_t *) malloc (sizeof (uwatec_memomouse_device_t)); + device = (uwatec_memomouse_device_t *) dc_device_allocate (context, &uwatec_memomouse_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &uwatec_memomouse_device_vtable); - // Set the default values. device->port = NULL; device->timestamp = 0; @@ -133,7 +131,7 @@ uwatec_memomouse_device_open (dc_device_t **out, dc_context_t *context, const ch error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/uwatec_memomouse_parser.c b/src/uwatec_memomouse_parser.c index 98fc25d..ce52200 100644 --- a/src/uwatec_memomouse_parser.c +++ b/src/uwatec_memomouse_parser.c @@ -44,6 +44,7 @@ static dc_status_t uwatec_memomouse_parser_get_field (dc_parser_t *abstract, dc_ static dc_status_t uwatec_memomouse_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t uwatec_memomouse_parser_vtable = { + sizeof(uwatec_memomouse_parser_t), DC_FAMILY_UWATEC_MEMOMOUSE, uwatec_memomouse_parser_set_data, /* set_data */ uwatec_memomouse_parser_get_datetime, /* datetime */ @@ -56,19 +57,18 @@ static const dc_parser_vtable_t uwatec_memomouse_parser_vtable = { dc_status_t uwatec_memomouse_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int devtime, dc_ticks_t systime) { + uwatec_memomouse_parser_t *parser = NULL; + if (out == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. - uwatec_memomouse_parser_t *parser = (uwatec_memomouse_parser_t *) malloc (sizeof (uwatec_memomouse_parser_t)); + parser = (uwatec_memomouse_parser_t *) dc_parser_allocate (context, &uwatec_memomouse_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &uwatec_memomouse_parser_vtable); - // Set the default values. parser->devtime = devtime; parser->systime = systime; diff --git a/src/uwatec_meridian.c b/src/uwatec_meridian.c index dda19bd..e8de867 100644 --- a/src/uwatec_meridian.c +++ b/src/uwatec_meridian.c @@ -55,6 +55,7 @@ static dc_status_t uwatec_meridian_device_foreach (dc_device_t *abstract, dc_div static dc_status_t uwatec_meridian_device_close (dc_device_t *abstract); static const dc_device_vtable_t uwatec_meridian_device_vtable = { + sizeof(uwatec_meridian_device_t), DC_FAMILY_UWATEC_MERIDIAN, uwatec_meridian_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -193,15 +194,12 @@ uwatec_meridian_device_open (dc_device_t **out, dc_context_t *context, const cha return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (uwatec_meridian_device_t *) malloc (sizeof (uwatec_meridian_device_t)); + device = (uwatec_meridian_device_t *) dc_device_allocate (context, &uwatec_meridian_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &uwatec_meridian_device_vtable); - // Set the default values. device->port = NULL; device->timestamp = 0; @@ -244,7 +242,7 @@ uwatec_meridian_device_open (dc_device_t **out, dc_context_t *context, const cha error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/uwatec_smart.c b/src/uwatec_smart.c index 2d45294..065943f 100644 --- a/src/uwatec_smart.c +++ b/src/uwatec_smart.c @@ -51,6 +51,7 @@ static dc_status_t uwatec_smart_device_foreach (dc_device_t *abstract, dc_dive_c static dc_status_t uwatec_smart_device_close (dc_device_t *abstract); static const dc_device_vtable_t uwatec_smart_device_vtable = { + sizeof(uwatec_smart_device_t), DC_FAMILY_UWATEC_SMART, uwatec_smart_device_set_fingerprint, /* set_fingerprint */ NULL, /* read */ @@ -152,15 +153,12 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context) return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (uwatec_smart_device_t *) malloc (sizeof (uwatec_smart_device_t)); + device = (uwatec_smart_device_t *) dc_device_allocate (context, &uwatec_smart_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &uwatec_smart_device_vtable); - // Set the default values. device->socket = NULL; device->address = 0; @@ -208,7 +206,7 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context) error_close: irda_socket_close (device->socket); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index 1fe57d7..eaa72d6 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -152,6 +152,7 @@ static dc_status_t uwatec_smart_parser_get_field (dc_parser_t *abstract, dc_fiel static dc_status_t uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static const dc_parser_vtable_t uwatec_smart_parser_vtable = { + sizeof(uwatec_smart_parser_t), DC_FAMILY_UWATEC_SMART, uwatec_smart_parser_set_data, /* set_data */ uwatec_smart_parser_get_datetime, /* datetime */ @@ -518,15 +519,12 @@ uwatec_smart_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i return DC_STATUS_INVALIDARGS; // Allocate memory. - parser = (uwatec_smart_parser_t *) malloc (sizeof (uwatec_smart_parser_t)); + parser = (uwatec_smart_parser_t *) dc_parser_allocate (context, &uwatec_smart_parser_vtable); if (parser == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - parser_init (&parser->base, context, &uwatec_smart_parser_vtable); - // Set the default values. parser->model = model; parser->devtime = devtime; @@ -620,7 +618,7 @@ uwatec_smart_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i return DC_STATUS_SUCCESS; error_free: - free (parser); + dc_parser_deallocate ((dc_parser_t *) parser); return status; } diff --git a/src/zeagle_n2ition3.c b/src/zeagle_n2ition3.c index ff7f8c2..ae76696 100644 --- a/src/zeagle_n2ition3.c +++ b/src/zeagle_n2ition3.c @@ -62,6 +62,7 @@ static dc_status_t zeagle_n2ition3_device_foreach (dc_device_t *abstract, dc_div static dc_status_t zeagle_n2ition3_device_close (dc_device_t *abstract); static const dc_device_vtable_t zeagle_n2ition3_device_vtable = { + sizeof(zeagle_n2ition3_device_t), DC_FAMILY_ZEAGLE_N2ITION3, zeagle_n2ition3_device_set_fingerprint, /* set_fingerprint */ zeagle_n2ition3_device_read, /* read */ @@ -144,15 +145,12 @@ zeagle_n2ition3_device_open (dc_device_t **out, dc_context_t *context, const cha return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (zeagle_n2ition3_device_t *) malloc (sizeof (zeagle_n2ition3_device_t)); + device = (zeagle_n2ition3_device_t *) dc_device_allocate (context, &zeagle_n2ition3_device_vtable); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &zeagle_n2ition3_device_vtable); - // Set the default values. device->port = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); @@ -193,7 +191,7 @@ zeagle_n2ition3_device_open (dc_device_t **out, dc_context_t *context, const cha error_close: serial_close (device->port); error_free: - free (device); + dc_device_deallocate ((dc_device_t *) device); return status; } From 0afa60bd977ecfe78ad156407e7828e86a34f8dd Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 7 Jan 2016 22:02:12 +0100 Subject: [PATCH 25/45] Return a more appropriate error code. The DC_STATUS_IO code is intended for reporting low-level I/O errors. That's not the case here, and there are more appropriate error codes available. --- src/hw_ostc3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index 9b81055..6f19bc4 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -385,7 +385,7 @@ hw_ostc3_device_init_service (hw_ostc3_device_t *device) output[2] != 0xCD || output[3] != 0xEF || output[4] != S_READY) { ERROR (context, "Failed to verify echo."); - return DC_STATUS_IO; + return DC_STATUS_PROTOCOL; } device->state = SERVICE; @@ -1011,7 +1011,7 @@ hw_ostc3_firmware_readfile (hw_ostc3_firmware_t *firmware, dc_context_t *context if (firmware->checksum != hw_ostc3_firmware_checksum (firmware)) { ERROR (context, "Failed to verify file checksum."); - return DC_STATUS_IO; + return DC_STATUS_DATAFORMAT; } return DC_STATUS_SUCCESS; From 9520ecddbc2a13504421de77bbcf9eae6f56c23d Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 10 Jan 2016 22:07:42 +0100 Subject: [PATCH 26/45] Add support for the Oceanic F11. This appears to be an Oceanic branded version of the Aeris F11. --- src/descriptor.c | 1 + src/oceanic_atom2.c | 3 ++- src/oceanic_atom2_parser.c | 23 +++++++++++++++-------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/descriptor.c b/src/descriptor.c index c5b3228..f1f23ce 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -179,6 +179,7 @@ static const dc_descriptor_t g_descriptors[] = { {"Aeris", "F11", DC_FAMILY_OCEANIC_ATOM2, 0x4549}, {"Oceanic", "OCi", DC_FAMILY_OCEANIC_ATOM2, 0x454B}, {"Aeris", "A300CS", DC_FAMILY_OCEANIC_ATOM2, 0x454C}, + {"Oceanic", "F11", DC_FAMILY_OCEANIC_ATOM2, 0x4554}, {"Oceanic", "VTX", DC_FAMILY_OCEANIC_ATOM2, 0x4557}, /* Mares Nemo */ {"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0}, diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index d19d82a..3deb761 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -86,7 +86,8 @@ static const oceanic_common_version_t aeris_f10_version[] = { }; static const oceanic_common_version_t aeris_f11_version[] = { - {"AERISF11 \0\0 1024"}, + {"AERISF11 \0\0 1024"}, + {"OCEANF11 \0\0 1024"}, }; static const oceanic_common_version_t oceanic_atom1_version[] = { diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 54188c2..d829047 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -70,9 +70,10 @@ #define AMPHOS 0x4545 #define AMPHOSAIR 0x4546 #define PROPLUS3 0x4548 -#define F11 0x4549 +#define F11A 0x4549 #define OCI 0x454B #define A300CS 0x454C +#define F11B 0x4554 #define VTX 0x4557 #define NORMAL 0 @@ -154,7 +155,7 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned } else if (model == F10) { parser->headersize = 3 * PAGESIZE; parser->footersize = PAGESIZE / 2; - } else if (model == F11) { + } else if (model == F11A || model == F11B) { parser->headersize = 5 * PAGESIZE; parser->footersize = PAGESIZE / 2; } else if (model == A300CS || model == VTX) { @@ -207,7 +208,8 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim oceanic_atom2_parser_t *parser = (oceanic_atom2_parser_t *) abstract; unsigned int header = 8; - if (parser->model == F10 || parser->model == F11) + if (parser->model == F10 || parser->model == F11A || + parser->model == F11B) header = 32; if (abstract->size < header) @@ -261,7 +263,8 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim datetime->minute = bcd2dec (p[0]); break; case F10: - case F11: + case F11A: + case F11B: datetime->year = bcd2dec (p[6]) + 2000; datetime->month = bcd2dec (p[7]); datetime->day = bcd2dec (p[8]); @@ -361,7 +364,8 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser) // Get the dive mode. unsigned int mode = NORMAL; - if (parser->model == F10 || parser->model == F11) { + if (parser->model == F10 || parser->model == F11A || + parser->model == F11B) { mode = FREEDIVE; } else if (parser->model == T3B || parser->model == VT3 || parser->model == DG03) { @@ -462,13 +466,15 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns if (value) { switch (type) { case DC_FIELD_DIVETIME: - if (parser->model == F10 || parser->model == F11) + if (parser->model == F10 || parser->model == F11A || + parser->model == F11B) *((unsigned int *) value) = bcd2dec (data[2]) + bcd2dec (data[3]) * 60 + bcd2dec (data[1]) * 3600; else *((unsigned int *) value) = parser->divetime; break; case DC_FIELD_MAXDEPTH: - if (parser->model == F10 || parser->model == F11) + if (parser->model == F10 || parser->model == F11A || + parser->model == F11B) *((double *) value) = array_uint16_le (data + 4) / 16.0 * FEET; else *((double *) value) = array_uint16_le (data + parser->footer + 4) / 16.0 * FEET; @@ -555,7 +561,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 == F11) { + if (parser->model == F10 || parser->model == F11A || + parser->model == F11B) { samplesize = 2; } else { samplesize = 4; From 9d856e5a369b3044211e4e1d8db3a11074057e20 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 11 Jan 2016 11:11:26 +0100 Subject: [PATCH 27/45] Fix the memory layout for the Oceanic F11. --- src/oceanic_atom2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 3deb761..67fa45a 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -198,9 +198,9 @@ static const oceanic_common_layout_t aeris_f11_layout = { 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0100, /* rb_logbook_begin */ - 0x0AC0, /* rb_logbook_end */ + 0x0D80, /* rb_logbook_end */ 32, /* rb_logbook_entry_size */ - 0xD810, /* rb_profile_begin */ + 0x0D80, /* rb_profile_begin */ 0x20000, /* rb_profile_end */ 0, /* pt_mode_global */ 3 /* pt_mode_logbook */ From 49af321bc5cff5cd3b0dc0b08ebf52e37801f85e Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 12 Jan 2016 22:37:46 +0100 Subject: [PATCH 28/45] Use the correct sample rate from the header. The Oceanic and Aeris F11 have a configurable sample rate. The possible sample intervals are 2, 1, 0.5 and 0.25 seconds. Since our smallest unit of time is one second, we can't represent the last two, and the extra samples will get dropped for now. --- src/oceanic_atom2_parser.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index d829047..268f963 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -539,6 +539,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ unsigned int time = 0; unsigned int interval = 1; + unsigned int samplerate = 1; if (parser->mode != FREEDIVE) { unsigned int idx = 0x17; if (parser->model == A300CS || parser->model == VTX) @@ -557,6 +558,30 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ interval = 60; break; } + } else if (parser->model == F11A || parser->model == F11B) { + unsigned int idx = 0x29; + switch (data[idx] & 0x03) { + case 0: + interval = 1; + samplerate = 4; + break; + case 1: + interval = 1; + samplerate = 2; + break; + case 2: + interval = 1; + break; + case 3: + interval = 2; + break; + } + if (samplerate > 1) { + // Some models supports multiple samples per second. + // Since our smallest unit of time is one second, we can't + // represent this, and the extra samples will get dropped. + WARNING(abstract->context, "Multiple samples per second are not supported!"); + } } unsigned int samplesize = PAGESIZE / 2; @@ -635,7 +660,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ // The sample size is usually fixed, but some sample types have a // larger size. Check whether we have that many bytes available. - unsigned int length = samplesize; + unsigned int length = samplesize * samplerate; if (sampletype == 0xBB) { length = PAGESIZE; if (offset + length > size - PAGESIZE) From ca032783a283d798ce4603ae527b379f5964f934 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 14 Jan 2016 10:50:08 +0100 Subject: [PATCH 29/45] Fix the decoding of the dive time. I originally assumed the second byte contains the hour, but that turns out to be wrong. At least some of the bits have a different meaning. With only seconds and minutes, the maximum divetime is limited to at most 99 minutes and 59 seconds. That shouldn't be a problem for freedives. --- src/oceanic_atom2_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 268f963..49cf13d 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -468,7 +468,7 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns case DC_FIELD_DIVETIME: if (parser->model == F10 || parser->model == F11A || parser->model == F11B) - *((unsigned int *) value) = bcd2dec (data[2]) + bcd2dec (data[3]) * 60 + bcd2dec (data[1]) * 3600; + *((unsigned int *) value) = bcd2dec (data[2]) + bcd2dec (data[3]) * 60; else *((unsigned int *) value) = parser->divetime; break; From 789fdb4d9afb79230acedb7d4a347ec7e6af0ca3 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sat, 16 Jan 2016 08:47:09 +0100 Subject: [PATCH 30/45] Remove the footer sample for the F10 and F11. The F10 and F11 don't seem to have a special footer sample after the profile data. Those 8 bytes appear to be valid sample data. --- src/oceanic_atom2_parser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 49cf13d..d52b379 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -154,10 +154,10 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned parser->headersize -= 2 * PAGESIZE; } else if (model == F10) { parser->headersize = 3 * PAGESIZE; - parser->footersize = PAGESIZE / 2; + parser->footersize = 0; } else if (model == F11A || model == F11B) { parser->headersize = 5 * PAGESIZE; - parser->footersize = PAGESIZE / 2; + parser->footersize = 0; } else if (model == A300CS || model == VTX) { parser->headersize = 5 * PAGESIZE; } From 6b3874121d189e4a672bc0915e890dc5e12690d9 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sat, 16 Jan 2016 17:03:06 +0100 Subject: [PATCH 31/45] Don't ignore zero depth samples in freedive mode. In freedive mode, samples are only 2 or 4 bytes large, thus a sample containing all 0x00 bytes represents a zero depth value and not some invalid data that should be ignored. --- src/oceanic_atom2_parser.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index d52b379..5dc3488 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -638,7 +638,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ dc_sample_value_t sample = {0}; // Ignore empty samples. - if (array_isequal (data + offset, samplesize, 0x00) || + if ((parser->mode != FREEDIVE && + array_isequal (data + offset, samplesize, 0x00)) || array_isequal (data + offset, samplesize, 0xFF)) { offset += samplesize; continue; From 4475d698142712dcdeb8c40526ed411003b1c2a4 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 21 Jan 2016 20:05:42 +0100 Subject: [PATCH 32/45] Use the error code returned by the WSAStartup function. Unlike the other socket functions, the WSAStartup() function returns the extended error code directly. A call to the WSAGetLastError() function is not needed and should not be used. --- src/irda.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/irda.c b/src/irda.c index 3be1151..a361eb8 100644 --- a/src/irda.c +++ b/src/irda.c @@ -90,8 +90,9 @@ irda_socket_open (irda_t **out, dc_context_t *context) // Initialize the winsock dll. WSADATA wsaData; WORD wVersionRequested = MAKEWORD (2, 2); - if (WSAStartup (wVersionRequested, &wsaData) != 0) { - SYSERROR (context, ERRNO); + int rc = WSAStartup (wVersionRequested, &wsaData); + if (rc != 0) { + SYSERROR (context, rc); goto error_free; } From 4228899f59f27002e36051ed4f5ac9c22690be47 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 21 Jan 2016 20:20:31 +0100 Subject: [PATCH 33/45] Reduce the conditional compilation for Windows. With a few compatibility macros and helper variables, the amount of conditional compilation can be greatly reduced. --- src/irda.c | 86 +++++++++++++++++++++--------------------------------- 1 file changed, 33 insertions(+), 53 deletions(-) diff --git a/src/irda.c b/src/irda.c index a361eb8..b0ee69e 100644 --- a/src/irda.c +++ b/src/irda.c @@ -43,9 +43,17 @@ #include "array.h" #ifdef _WIN32 -#define ERRNO WSAGetLastError () +#define S_ERRNO WSAGetLastError () +#define S_EAGAIN WSAEWOULDBLOCK +#define S_INVALID INVALID_SOCKET +#define S_IOCTL ioctlsocket +#define S_CLOSE closesocket #else -#define ERRNO errno +#define S_ERRNO errno +#define S_EAGAIN EAGAIN +#define S_INVALID -1 +#define S_IOCTL ioctl +#define S_CLOSE close #endif #ifdef _MSC_VER @@ -108,12 +116,8 @@ irda_socket_open (irda_t **out, dc_context_t *context) // Open the socket. device->fd = socket (AF_IRDA, SOCK_STREAM, 0); -#ifdef _WIN32 - if (device->fd == INVALID_SOCKET) { -#else - if (device->fd == -1) { -#endif - SYSERROR (context, ERRNO); + if (device->fd == S_INVALID) { + SYSERROR (context, S_ERRNO); goto error_wsacleanup; } @@ -143,19 +147,15 @@ irda_socket_close (irda_t *device) shutdown (device->fd, 0); // Close the socket. -#ifdef _WIN32 - if (closesocket (device->fd) != 0) { -#else - if (close (device->fd) != 0) { -#endif - SYSERROR (device->context, ERRNO); + if (S_CLOSE (device->fd) != 0) { + SYSERROR (device->context, S_ERRNO); errcode = -1; } #ifdef _WIN32 // Terminate the winsock dll. if (WSACleanup () != 0) { - SYSERROR (device->context, ERRNO); + SYSERROR (device->context, S_ERRNO); errcode = -1; } #endif @@ -221,12 +221,8 @@ irda_socket_discover (irda_t *device, irda_callback_t callback, void *userdata) // discovered, while on Windows it succeeds and sets the number // of devices to zero. Both situations are handled the same here. if (rc != 0) { -#ifdef _WIN32 - if (WSAGetLastError() != WSAEWOULDBLOCK) { -#else - if (errno != EAGAIN) { -#endif - SYSERROR (device->context, ERRNO); + if (S_ERRNO != S_EAGAIN) { + SYSERROR (device->context, S_ERRNO); return -1; // Error during getsockopt call. } } @@ -249,41 +245,25 @@ irda_socket_discover (irda_t *device, irda_callback_t callback, void *userdata) if (callback) { #ifdef _WIN32 for (unsigned int i = 0; i < list->numDevice; ++i) { + const char *name = list->Device[i].irdaDeviceName; unsigned int address = array_uint32_le (list->Device[i].irdaDeviceID); + unsigned int charset = list->Device[i].irdaCharSet; unsigned int hints = (list->Device[i].irdaDeviceHints1 << 8) + list->Device[i].irdaDeviceHints2; - - INFO (device->context, - "Discover: address=%08x, name=%s, charset=%02x, hints=%04x", - address, - list->Device[i].irdaDeviceName, - list->Device[i].irdaCharSet, - hints); - - callback (address, - list->Device[i].irdaDeviceName, - list->Device[i].irdaCharSet, - hints, - userdata); - } #else for (unsigned int i = 0; i < list->len; ++i) { + const char *name = list->dev[i].info; + unsigned int address = list->dev[i].daddr; + unsigned int charset = list->dev[i].charset; unsigned int hints = array_uint16_be (list->dev[i].hints); +#endif INFO (device->context, "Discover: address=%08x, name=%s, charset=%02x, hints=%04x", - list->dev[i].daddr, - list->dev[i].info, - list->dev[i].charset, - hints); + address, name, charset, hints); - callback (list->dev[i].daddr, - list->dev[i].info, - list->dev[i].charset, - hints, - userdata); + callback (address, name, charset, hints, userdata); } -#endif } return 0; @@ -320,7 +300,7 @@ irda_socket_connect_name (irda_t *device, unsigned int address, const char *name #endif if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) { - SYSERROR (device->context, ERRNO); + SYSERROR (device->context, S_ERRNO); return -1; } @@ -352,7 +332,7 @@ irda_socket_connect_lsap (irda_t *device, unsigned int address, unsigned int lsa #endif if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) { - SYSERROR (device->context, ERRNO); + SYSERROR (device->context, S_ERRNO); return -1; } @@ -368,12 +348,12 @@ irda_socket_available (irda_t *device) #ifdef _WIN32 unsigned long bytes = 0; - if (ioctlsocket (device->fd, FIONREAD, &bytes) != 0) { #else int bytes = 0; - if (ioctl (device->fd, FIONREAD, &bytes) != 0) { #endif - SYSERROR (device->context, ERRNO); + + if (S_IOCTL (device->fd, FIONREAD, &bytes) != 0) { + SYSERROR (device->context, S_ERRNO); return -1; } @@ -401,7 +381,7 @@ irda_socket_read (irda_t *device, void *data, unsigned int size) while (nbytes < size) { int rc = select (device->fd + 1, &fds, NULL, NULL, (device->timeout >= 0 ? &tv : NULL)); if (rc < 0) { - SYSERROR (device->context, ERRNO); + SYSERROR (device->context, S_ERRNO); return -1; // Error during select call. } else if (rc == 0) { break; // Timeout. @@ -409,7 +389,7 @@ irda_socket_read (irda_t *device, void *data, unsigned int size) int n = recv (device->fd, (char*) data + nbytes, size - nbytes, 0); if (n < 0) { - SYSERROR (device->context, ERRNO); + SYSERROR (device->context, S_ERRNO); return -1; // Error during recv call. } else if (n == 0) { break; // EOF reached. @@ -434,7 +414,7 @@ irda_socket_write (irda_t *device, const void *data, unsigned int size) while (nbytes < size) { int n = send (device->fd, (char*) data + nbytes, size - nbytes, 0); if (n < 0) { - SYSERROR (device->context, ERRNO); + SYSERROR (device->context, S_ERRNO); return -1; // Error during send call. } From ade8619ea65e415394f648a44b8350de40a17951 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 26 Jan 2016 19:33:46 +0100 Subject: [PATCH 34/45] Don't assume malloc sets errno to ENOMEM. Although many implementations (including glibc) set errno on failure, this is not required by the C standard. --- src/irda.c | 2 +- src/serial_posix.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/irda.c b/src/irda.c index b0ee69e..57b5076 100644 --- a/src/irda.c +++ b/src/irda.c @@ -83,7 +83,7 @@ irda_socket_open (irda_t **out, dc_context_t *context) #ifdef _WIN32 SYSERROR (context, ERROR_OUTOFMEMORY); #else - SYSERROR (context, errno); + SYSERROR (context, ENOMEM); #endif return -1; // ENOMEM (Not enough space) } diff --git a/src/serial_posix.c b/src/serial_posix.c index ffd4047..b67ddb7 100644 --- a/src/serial_posix.c +++ b/src/serial_posix.c @@ -137,7 +137,7 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) // Allocate memory. serial_t *device = (serial_t *) malloc (sizeof (serial_t)); if (device == NULL) { - SYSERROR (context, errno); + SYSERROR (context, ENOMEM); return -1; // ENOMEM (Not enough space) } From 5add68b2d5d60d623ad6fb40d1e63b1bdd2da632 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 27 Jan 2016 23:41:51 +0100 Subject: [PATCH 35/45] Use the optreset variable on BSD systems. On BSD based operating systems the optreset variable should be used to reset the internal getopt state. Setting optind to zero is a GNU extension. --- configure.ac | 3 +++ examples/dctool.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/configure.ac b/configure.ac index ca071fa..cb9c7a3 100644 --- a/configure.ac +++ b/configure.ac @@ -107,6 +107,9 @@ AC_CHECK_HEADERS([linux/serial.h]) AC_CHECK_HEADERS([IOKit/serial/ioss.h]) AC_CHECK_HEADERS([getopt.h]) +# Checks for global variable declarations. +AC_CHECK_DECLS([optreset]) + # Checks for library functions. AC_FUNC_STRERROR_R AC_CHECK_FUNCS([localtime_r gmtime_r]) diff --git a/examples/dctool.c b/examples/dctool.c index 4d70c0e..c3ac6c0 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -217,6 +217,9 @@ main (int argc, char *argv[]) argc -= optind; argv += optind; optind = RESET; +#if defined(HAVE_DECL_OPTRESET) && HAVE_DECL_OPTRESET + optreset = 1; +#endif // Translate the help option into a command. char *argv_help[] = {(char *) "help", NULL, NULL}; From 67a3697a4d90233cad53d2770b2204e8f39e1668 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 27 Jan 2016 23:49:13 +0100 Subject: [PATCH 36/45] Disable the getopt argument permutation on BSD systems. On BSD based operating systems (which includes Mac OS X), the getopt() function is posix compliant and thus the option processing stops when the first non-option is found. But the getopt_long() function permutes the argument vector, just like the GNU implementation. Using a leading '+' character in the option string disables the permutation again. --- configure.ac | 1 + examples/dctool.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index cb9c7a3..b5aa34b 100644 --- a/configure.ac +++ b/configure.ac @@ -106,6 +106,7 @@ AM_CONDITIONAL([IRDA], [test "$irda_win32" = "yes" || test "$irda_linux" = "yes" AC_CHECK_HEADERS([linux/serial.h]) AC_CHECK_HEADERS([IOKit/serial/ioss.h]) AC_CHECK_HEADERS([getopt.h]) +AC_CHECK_HEADERS([sys/param.h]) # Checks for global variable declarations. AC_CHECK_DECLS([optreset]) diff --git a/examples/dctool.c b/examples/dctool.c index c3ac6c0..a317980 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -31,6 +31,9 @@ #ifdef HAVE_GETOPT_H #include #endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif #include #include @@ -40,13 +43,17 @@ #include "utils.h" #if defined(__GLIBC__) || defined(__MINGW32__) -#define NOPERMUTATION "+" #define RESET 0 #else -#define NOPERMUTATION "" #define RESET 1 #endif +#if defined(__GLIBC__) || defined(__MINGW32__) || defined(BSD) +#define NOPERMUTATION "+" +#else +#define NOPERMUTATION "" +#endif + static const dctool_command_t *g_commands[] = { &dctool_help, &dctool_version, From d2e150319b96049516e69ad3ba87cf4cd254e095 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 4 Feb 2016 08:31:44 +0100 Subject: [PATCH 37/45] Fix the decoding of negative temperatures. Due to a firmware bug, negative temperatures are stored incorrectly and a workaround is necessary to recover the correct value. --- src/shearwater_predator_parser.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index f1a5c31..71c09c7 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -389,7 +389,14 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata); // Temperature (°C or °F). - unsigned int temperature = data[offset + 13]; + int temperature = (signed char) data[offset + 13]; + if (temperature < 0) { + // Fix negative temperatures. + temperature += 102; + if (temperature > 0) { + temperature = 0; + } + } if (units == IMPERIAL) sample.temperature = (temperature - 32.0) * (5.0 / 9.0); else From aafdbe8baadf5eeacc7a47f5b5cb301a2b6f99c7 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 16 Feb 2016 20:34:01 +0100 Subject: [PATCH 38/45] Fix the date for the Oceanic Datamask. --- src/oceanic_atom2_parser.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 5dc3488..fe6ed85 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -246,6 +246,8 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim case T3B: case GEO20: case PROPLUS3: + case DATAMASK: + case COMPUMASK: datetime->year = ((p[3] & 0xE0) >> 1) + (p[4] & 0x0F) + 2000; datetime->month = (p[4] & 0xF0) >> 4; datetime->day = p[3] & 0x1F; From 4765f7bc500d0caf22cadd7df81a356313762d7a Mon Sep 17 00:00:00 2001 From: Janice Date: Fri, 19 Feb 2016 10:25:57 -0800 Subject: [PATCH 39/45] Fix year decoding for Sherwood Amphos Air --- src/oceanic_atom2_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index fe6ed85..a6d0aa1 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -258,7 +258,7 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim case AMPHOS: case AMPHOSAIR: case VOYAGER2G: - datetime->year = (p[3] & 0x0F) + 2000; + datetime->year = (p[3] & 0x1F) + 2000; datetime->month = (p[7] & 0xF0) >> 4; datetime->day = ((p[3] & 0x80) >> 3) + ((p[5] & 0xF0) >> 4); datetime->hour = bcd2dec (p[1] & 0x1F); From 195702046c9f2a1d6a1445c2735a634227838043 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sat, 6 Feb 2016 15:27:40 +0100 Subject: [PATCH 40/45] Add a new abstract output interface. The new output interface provides the necessary infrastructure to add support for multiple output formats. Due to the abstract interface, each new format will require only minimal changes in the application itself. --- examples/Makefile.am | 3 ++ examples/output-private.h | 58 ++++++++++++++++++++++++++++ examples/output.c | 79 +++++++++++++++++++++++++++++++++++++++ examples/output.h | 43 +++++++++++++++++++++ 4 files changed, 183 insertions(+) create mode 100644 examples/output-private.h create mode 100644 examples/output.c create mode 100644 examples/output.h diff --git a/examples/Makefile.am b/examples/Makefile.am index cb13b64..a05af08 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -17,5 +17,8 @@ dctool_SOURCES = \ dctool_read.c \ dctool_write.c \ dctool_fwupdate.c \ + output.h \ + output-private.h \ + output.c \ utils.h \ utils.c diff --git a/examples/output-private.h b/examples/output-private.h new file mode 100644 index 0000000..db8cb06 --- /dev/null +++ b/examples/output-private.h @@ -0,0 +1,58 @@ +/* + * libdivecomputer + * + * Copyright (C) 2016 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef DCTOOL_OUTPUT_PRIVATE_H +#define DCTOOL_OUTPUT_PRIVATE_H + +#include +#include + +#include "output.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct dctool_output_vtable_t dctool_output_vtable_t; + +struct dctool_output_t { + const dctool_output_vtable_t *vtable; + unsigned int number; +}; + +struct dctool_output_vtable_t { + size_t size; + + dc_status_t (*write) (dctool_output_t *output, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize); + + dc_status_t (*free) (dctool_output_t *output); +}; + +dctool_output_t * +dctool_output_allocate (const dctool_output_vtable_t *vtable); + +void +dctool_output_deallocate (dctool_output_t *output); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DCTOOL_OUTPUT_PRIVATE_H */ diff --git a/examples/output.c b/examples/output.c new file mode 100644 index 0000000..510c929 --- /dev/null +++ b/examples/output.c @@ -0,0 +1,79 @@ +/* + * libdivecomputer + * + * Copyright (C) 2016 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include + +#include "output-private.h" + +dctool_output_t * +dctool_output_allocate (const dctool_output_vtable_t *vtable) +{ + dctool_output_t *output = NULL; + + assert(vtable != NULL); + assert(vtable->size >= sizeof(dctool_output_t)); + + // Allocate memory. + output = (dctool_output_t *) malloc (vtable->size); + if (output == NULL) { + return output; + } + + output->vtable = vtable; + output->number = 0; + + return output; +} + +void +dctool_output_deallocate (dctool_output_t *output) +{ + free (output); +} + +dc_status_t +dctool_output_write (dctool_output_t *output, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize) +{ + if (output == NULL || output->vtable->write == NULL) + return DC_STATUS_SUCCESS; + + output->number++; + + return output->vtable->write (output, parser, data, size, fingerprint, fsize); +} + +dc_status_t +dctool_output_free (dctool_output_t *output) +{ + dc_status_t status = DC_STATUS_SUCCESS; + + if (output == NULL) + return DC_STATUS_SUCCESS; + + if (output->vtable->free) { + status = output->vtable->free (output); + } + + dctool_output_deallocate (output); + + return status; +} diff --git a/examples/output.h b/examples/output.h new file mode 100644 index 0000000..b11675f --- /dev/null +++ b/examples/output.h @@ -0,0 +1,43 @@ +/* + * libdivecomputer + * + * Copyright (C) 2016 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef DCTOOL_OUTPUT_H +#define DCTOOL_OUTPUT_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef struct dctool_output_t dctool_output_t; + +dc_status_t +dctool_output_write (dctool_output_t *output, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize); + +dc_status_t +dctool_output_free (dctool_output_t *output); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DCTOOL_OUTPUT_H */ From e35f0a3ff45dde9114bba1c896b64c226c065a78 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sat, 6 Feb 2016 15:35:08 +0100 Subject: [PATCH 41/45] Add support for the xml output format. The XML output format exports all dives to a single xml file. --- examples/Makefile.am | 1 + examples/output.h | 3 + examples/output_xml.c | 365 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 369 insertions(+) create mode 100644 examples/output_xml.c diff --git a/examples/Makefile.am b/examples/Makefile.am index a05af08..3ae96d5 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -20,5 +20,6 @@ dctool_SOURCES = \ output.h \ output-private.h \ output.c \ + output_xml.c \ utils.h \ utils.c diff --git a/examples/output.h b/examples/output.h index b11675f..b123689 100644 --- a/examples/output.h +++ b/examples/output.h @@ -31,6 +31,9 @@ extern "C" { typedef struct dctool_output_t dctool_output_t; +dctool_output_t * +dctool_xml_output_new (const char *filename); + dc_status_t dctool_output_write (dctool_output_t *output, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize); diff --git a/examples/output_xml.c b/examples/output_xml.c new file mode 100644 index 0000000..a36e62a --- /dev/null +++ b/examples/output_xml.c @@ -0,0 +1,365 @@ +/* + * libdivecomputer + * + * Copyright (C) 2016 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include + +#include "output-private.h" +#include "utils.h" + +static dc_status_t dctool_xml_output_write (dctool_output_t *output, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize); +static dc_status_t dctool_xml_output_free (dctool_output_t *output); + +typedef struct dctool_xml_output_t { + dctool_output_t base; + FILE *ostream; +} dctool_xml_output_t; + +static const dctool_output_vtable_t xml_vtable = { + sizeof(dctool_xml_output_t), /* size */ + dctool_xml_output_write, /* write */ + dctool_xml_output_free, /* free */ +}; + +typedef struct sample_data_t { + FILE *ostream; + unsigned int nsamples; +} sample_data_t; + +static void +sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata) +{ + static const char *events[] = { + "none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter", + "violation", "bookmark", "surface", "safety stop", "gaschange", + "safety stop (voluntary)", "safety stop (mandatory)", "deepstop", + "ceiling (safety stop)", "floor", "divetime", "maxdepth", + "OLF", "PO2", "airtime", "rgbm", "heading", "tissue level warning", + "gaschange2"}; + static const char *decostop[] = { + "ndl", "safety", "deco", "deep"}; + + sample_data_t *sampledata = (sample_data_t *) userdata; + + switch (type) { + case DC_SAMPLE_TIME: + if (sampledata->nsamples++) + fprintf (sampledata->ostream, "\n"); + fprintf (sampledata->ostream, "\n"); + fprintf (sampledata->ostream, " \n", value.time / 60, value.time % 60); + break; + case DC_SAMPLE_DEPTH: + fprintf (sampledata->ostream, " %.2f\n", value.depth); + break; + case DC_SAMPLE_PRESSURE: + fprintf (sampledata->ostream, " %.2f\n", value.pressure.tank, value.pressure.value); + break; + case DC_SAMPLE_TEMPERATURE: + fprintf (sampledata->ostream, " %.2f\n", value.temperature); + break; + case DC_SAMPLE_EVENT: + if (value.event.type != SAMPLE_EVENT_GASCHANGE && value.event.type != SAMPLE_EVENT_GASCHANGE2) { + fprintf (sampledata->ostream, " %s\n", + value.event.type, value.event.time, value.event.flags, value.event.value, events[value.event.type]); + } + break; + case DC_SAMPLE_RBT: + fprintf (sampledata->ostream, " %u\n", value.rbt); + break; + case DC_SAMPLE_HEARTBEAT: + fprintf (sampledata->ostream, " %u\n", value.heartbeat); + break; + case DC_SAMPLE_BEARING: + fprintf (sampledata->ostream, " %u\n", value.bearing); + break; + case DC_SAMPLE_VENDOR: + fprintf (sampledata->ostream, " ", value.vendor.type, value.vendor.size); + for (unsigned int i = 0; i < value.vendor.size; ++i) + fprintf (sampledata->ostream, "%02X", ((unsigned char *) value.vendor.data)[i]); + fprintf (sampledata->ostream, "\n"); + break; + case DC_SAMPLE_SETPOINT: + fprintf (sampledata->ostream, " %.2f\n", value.setpoint); + break; + case DC_SAMPLE_PPO2: + fprintf (sampledata->ostream, " %.2f\n", value.ppo2); + break; + case DC_SAMPLE_CNS: + fprintf (sampledata->ostream, " %.1f\n", value.cns * 100.0); + break; + case DC_SAMPLE_DECO: + fprintf (sampledata->ostream, " %s\n", + value.deco.time, value.deco.depth, decostop[value.deco.type]); + break; + case DC_SAMPLE_GASMIX: + fprintf (sampledata->ostream, " %u\n", value.gasmix); + break; + default: + break; + } +} + +dctool_output_t * +dctool_xml_output_new (const char *filename) +{ + dctool_xml_output_t *output = NULL; + + if (filename == NULL) + goto error_exit; + + // Allocate memory. + output = (dctool_xml_output_t *) dctool_output_allocate (&xml_vtable); + if (output == NULL) { + goto error_exit; + } + + // Open the output file. + output->ostream = fopen (filename, "w"); + if (output->ostream == NULL) { + goto error_free; + } + + fprintf (output->ostream, "\n"); + + return (dctool_output_t *) output; + +error_free: + dctool_output_deallocate ((dctool_output_t *) output); +error_exit: + return NULL; +} + +static dc_status_t +dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize) +{ + dctool_xml_output_t *output = (dctool_xml_output_t *) abstract; + dc_status_t status = DC_STATUS_SUCCESS; + + fprintf (output->ostream, "\n%u\n%u\n", abstract->number, size); + + if (fingerprint) { + fprintf (output->ostream, ""); + for (unsigned int i = 0; i < fsize; ++i) + fprintf (output->ostream, "%02X", fingerprint[i]); + fprintf (output->ostream, "\n"); + } + + // Parse the datetime. + message ("Parsing the datetime.\n"); + dc_datetime_t dt = {0}; + status = dc_parser_get_datetime (parser, &dt); + if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the datetime."); + goto cleanup; + } + + fprintf (output->ostream, "%04i-%02i-%02i %02i:%02i:%02i\n", + dt.year, dt.month, dt.day, + dt.hour, dt.minute, dt.second); + + // Parse the divetime. + message ("Parsing the divetime.\n"); + unsigned int divetime = 0; + status = dc_parser_get_field (parser, DC_FIELD_DIVETIME, 0, &divetime); + if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the divetime."); + goto cleanup; + } + + fprintf (output->ostream, "%02u:%02u\n", + divetime / 60, divetime % 60); + + // Parse the maxdepth. + message ("Parsing the maxdepth.\n"); + double maxdepth = 0.0; + status = dc_parser_get_field (parser, DC_FIELD_MAXDEPTH, 0, &maxdepth); + if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the maxdepth."); + goto cleanup; + } + + fprintf (output->ostream, "%.2f\n", + maxdepth); + + // Parse the temperature. + message ("Parsing the temperature.\n"); + for (unsigned int i = 0; i < 3; ++i) { + dc_field_type_t fields[] = {DC_FIELD_TEMPERATURE_SURFACE, + DC_FIELD_TEMPERATURE_MINIMUM, + DC_FIELD_TEMPERATURE_MAXIMUM}; + const char *names[] = {"surface", "minimum", "maximum"}; + + double temperature = 0.0; + status = dc_parser_get_field (parser, fields[i], 0, &temperature); + if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the temperature."); + goto cleanup; + } + + if (status != DC_STATUS_UNSUPPORTED) { + fprintf (output->ostream, "%.1f\n", + names[i], temperature); + } + } + + // Parse the gas mixes. + message ("Parsing the gas mixes.\n"); + unsigned int ngases = 0; + status = dc_parser_get_field (parser, DC_FIELD_GASMIX_COUNT, 0, &ngases); + if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the gas mix count."); + goto cleanup; + } + + for (unsigned int i = 0; i < ngases; ++i) { + dc_gasmix_t gasmix = {0}; + status = dc_parser_get_field (parser, DC_FIELD_GASMIX, i, &gasmix); + if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the gas mix."); + goto cleanup; + } + + fprintf (output->ostream, + "\n" + " %.1f\n" + " %.1f\n" + " %.1f\n" + "\n", + gasmix.helium * 100.0, + gasmix.oxygen * 100.0, + gasmix.nitrogen * 100.0); + } + + // Parse the tanks. + message ("Parsing the tanks.\n"); + unsigned int ntanks = 0; + status = dc_parser_get_field (parser, DC_FIELD_TANK_COUNT, 0, &ntanks); + if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the tank count."); + goto cleanup; + } + + for (unsigned int i = 0; i < ntanks; ++i) { + const char *names[] = {"none", "metric", "imperial"}; + + dc_tank_t tank = {0}; + status = dc_parser_get_field (parser, DC_FIELD_TANK, i, &tank); + if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the tank."); + goto cleanup; + } + + fprintf (output->ostream, "\n"); + if (tank.gasmix != DC_GASMIX_UNKNOWN) { + fprintf (output->ostream, + " %u\n", + tank.gasmix); + } + if (tank.type != DC_TANKVOLUME_NONE) { + fprintf (output->ostream, + " %s\n" + " %.1f\n" + " %.2f\n", + names[tank.type], tank.volume, tank.workpressure); + } + fprintf (output->ostream, + " %.2f\n" + " %.2f\n" + "\n", + tank.beginpressure, tank.endpressure); + } + + // Parse the dive mode. + message ("Parsing the dive mode.\n"); + dc_divemode_t divemode = DC_DIVEMODE_OC; + status = dc_parser_get_field (parser, DC_FIELD_DIVEMODE, 0, &divemode); + if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the dive mode."); + goto cleanup; + } + + if (status != DC_STATUS_UNSUPPORTED) { + const char *names[] = {"freedive", "gauge", "oc", "cc"}; + fprintf (output->ostream, "%s\n", + names[divemode]); + } + + // Parse the salinity. + message ("Parsing the salinity.\n"); + dc_salinity_t salinity = {DC_WATER_FRESH, 0.0}; + status = dc_parser_get_field (parser, DC_FIELD_SALINITY, 0, &salinity); + if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the salinity."); + goto cleanup; + } + + if (status != DC_STATUS_UNSUPPORTED) { + fprintf (output->ostream, "%.1f\n", + salinity.type, salinity.density); + } + + // Parse the atmospheric pressure. + message ("Parsing the atmospheric pressure.\n"); + double atmospheric = 0.0; + status = dc_parser_get_field (parser, DC_FIELD_ATMOSPHERIC, 0, &atmospheric); + if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the atmospheric pressure."); + goto cleanup; + } + + if (status != DC_STATUS_UNSUPPORTED) { + fprintf (output->ostream, "%.5f\n", + atmospheric); + } + + // Initialize the sample data. + sample_data_t sampledata = {0}; + sampledata.nsamples = 0; + sampledata.ostream = output->ostream; + + // Parse the sample data. + message ("Parsing the sample data.\n"); + status = dc_parser_samples_foreach (parser, sample_cb, &sampledata); + if (status != DC_STATUS_SUCCESS) { + ERROR ("Error parsing the sample data."); + goto cleanup; + } + + if (sampledata.nsamples) + fprintf (output->ostream, "\n"); + fprintf (output->ostream, "\n"); + +cleanup: + return status; +} + +static dc_status_t +dctool_xml_output_free (dctool_output_t *abstract) +{ + dctool_xml_output_t *output = (dctool_xml_output_t *) abstract; + + fprintf (output->ostream, "\n"); + + fclose (output->ostream); + + return DC_STATUS_SUCCESS; +} From 5d9ddafc41a7889119953ecba810c227f72c65f5 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sat, 6 Feb 2016 15:37:27 +0100 Subject: [PATCH 42/45] Add support for the raw output format. The RAW output format exports each dive to a raw (binary) file. To output multiple files, the filename is interpreted as a template and should contain one or more placeholders. --- examples/Makefile.am | 1 + examples/output.h | 3 + examples/output_raw.c | 219 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 examples/output_raw.c diff --git a/examples/Makefile.am b/examples/Makefile.am index 3ae96d5..4c1aa05 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -21,5 +21,6 @@ dctool_SOURCES = \ output-private.h \ output.c \ output_xml.c \ + output_raw.c \ utils.h \ utils.c diff --git a/examples/output.h b/examples/output.h index b123689..0912de2 100644 --- a/examples/output.h +++ b/examples/output.h @@ -34,6 +34,9 @@ typedef struct dctool_output_t dctool_output_t; dctool_output_t * dctool_xml_output_new (const char *filename); +dctool_output_t * +dctool_raw_output_new (const char *template); + dc_status_t dctool_output_write (dctool_output_t *output, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize); diff --git a/examples/output_raw.c b/examples/output_raw.c new file mode 100644 index 0000000..951531e --- /dev/null +++ b/examples/output_raw.c @@ -0,0 +1,219 @@ +/* + * libdivecomputer + * + * Copyright (C) 2016 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include +#include +#include + +#include "output-private.h" +#include "utils.h" + +static dc_status_t dctool_raw_output_write (dctool_output_t *output, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize); +static dc_status_t dctool_raw_output_free (dctool_output_t *output); + +typedef struct dctool_raw_output_t { + dctool_output_t base; + char *template; +} dctool_raw_output_t; + +static const dctool_output_vtable_t raw_vtable = { + sizeof(dctool_raw_output_t), /* size */ + dctool_raw_output_write, /* write */ + dctool_raw_output_free, /* free */ +}; + +static int +mktemplate_fingerprint (char *buffer, size_t size, const unsigned char fingerprint[], size_t fsize) +{ + const unsigned char ascii[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + if (size < 2 * fsize + 1) + return -1; + + for (size_t i = 0; i < fsize; ++i) { + // Set the most-significant nibble. + unsigned char msn = (fingerprint[i] >> 4) & 0x0F; + buffer[i * 2 + 0] = ascii[msn]; + + // Set the least-significant nibble. + unsigned char lsn = fingerprint[i] & 0x0F; + buffer[i * 2 + 1] = ascii[lsn]; + } + + // Null-terminate the string. + buffer[fsize * 2] = 0; + + return fsize * 2; +} + +static int +mktemplate_datetime (char *buffer, size_t size, dc_parser_t *parser) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + dc_datetime_t datetime = {0}; + int n = 0; + + rc = dc_parser_get_datetime (parser, &datetime); + if (rc != DC_STATUS_SUCCESS) + return -1; + + n = snprintf (buffer, size, "%04i%02i%02iT%02i%02i%02i", + datetime.year, datetime.month, datetime.day, + datetime.hour, datetime.minute, datetime.second); + if (n < 0 || n >= size) + return -1; + + return n; +} + +static int +mktemplate_number (char *buffer, size_t size, unsigned int number) +{ + int n = 0; + + n = snprintf (buffer, size, "%04u", number); + if (n < 0 || n >= size) + return -1; + + return n; +} + +static int +mktemplate (char *buffer, size_t size, const char *format, dc_parser_t *parser, const unsigned char fingerprint[], size_t fsize, unsigned int number) +{ + const char *p = format; + size_t n = 0; + int len = 0; + char ch = 0; + + while ((ch = *p++) != 0) { + if (ch != '%') { + if (n >= size) + return -1; + buffer[n] = ch; + n++; + continue; + } + + ch = *p++; + switch (ch) { + case '%': + if (n >= size) + return -1; + buffer[n] = ch; + n++; + break; + case 't': // Timestamp + len = mktemplate_datetime (buffer + n, size - n, parser); + if (len < 0) + return -1; + n += len; + break; + case 'f': // Fingerprint + len = mktemplate_fingerprint (buffer + n, size - n, fingerprint, fsize); + if (len < 0) + return -1; + n += len; + break; + case 'n': // Number + len = mktemplate_number (buffer + n, size - n, number); + if (len < 0) + return -1; + n += len; + break; + default: + return -1; + } + } + + // Null-terminate the string + if (n >= size) + return -1; + buffer[n] = 0; + + return n; +} + +dctool_output_t * +dctool_raw_output_new (const char *template) +{ + dctool_raw_output_t *output = NULL; + + if (template == NULL) + goto error_exit; + + // Allocate memory. + output = (dctool_raw_output_t *) dctool_output_allocate (&raw_vtable); + if (output == NULL) { + goto error_exit; + } + + output->template = strdup(template); + if (output->template == NULL) { + goto error_free; + } + + return (dctool_output_t *) output; + +error_free: + dctool_output_deallocate ((dctool_output_t *) output); +error_exit: + return NULL; +} + +static dc_status_t +dctool_raw_output_write (dctool_output_t *abstract, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize) +{ + dctool_raw_output_t *output = (dctool_raw_output_t *) abstract; + + // Generate the filename. + char name[1024] = {0}; + int ret = mktemplate (name, sizeof(name), output->template, parser, fingerprint, fsize, abstract->number); + if (ret < 0) { + ERROR("Failed to generate filename from template."); + return DC_STATUS_SUCCESS; + } + + // Open the output file. + FILE *fp = fopen (name, "wb"); + if (fp == NULL) { + ERROR("Failed to open the output file."); + return DC_STATUS_SUCCESS; + } + + // Write the data. + fwrite (data, sizeof (unsigned char), size, fp); + fclose (fp); + + return DC_STATUS_SUCCESS; +} + +static dc_status_t +dctool_raw_output_free (dctool_output_t *abstract) +{ + dctool_raw_output_t *output = (dctool_raw_output_t *) abstract; + + free (output->template); + + return DC_STATUS_SUCCESS; +} From e8b9e881714b62e57c35320b3d58beb8b0914de8 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sat, 6 Feb 2016 15:58:23 +0100 Subject: [PATCH 43/45] Integrate the new output formats. The existing output code is removed and replaced with the new XML and RAW output formats. The desired output format can be selected with a new command-line option. The XML format remains the default output format. --- examples/dctool_download.c | 380 +++++++------------------------------ 1 file changed, 70 insertions(+), 310 deletions(-) diff --git a/examples/dctool_download.c b/examples/dctool_download.c index 61c4127..4baa333 100644 --- a/examples/dctool_download.c +++ b/examples/dctool_download.c @@ -38,6 +38,7 @@ #include "dctool.h" #include "common.h" +#include "output.h" #include "utils.h" typedef struct event_data_t { @@ -46,305 +47,18 @@ typedef struct event_data_t { } event_data_t; typedef struct dive_data_t { - FILE* ostream; dc_device_t *device; dc_buffer_t **fingerprint; unsigned int number; + dctool_output_t *output; } dive_data_t; -typedef struct sample_data_t { - FILE* ostream; - unsigned int nsamples; -} sample_data_t; - -static void -sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata) -{ - static const char *events[] = { - "none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter", - "violation", "bookmark", "surface", "safety stop", "gaschange", - "safety stop (voluntary)", "safety stop (mandatory)", "deepstop", - "ceiling (safety stop)", "floor", "divetime", "maxdepth", - "OLF", "PO2", "airtime", "rgbm", "heading", "tissue level warning", - "gaschange2"}; - static const char *decostop[] = { - "ndl", "safety", "deco", "deep"}; - - sample_data_t *sampledata = (sample_data_t *) userdata; - - switch (type) { - case DC_SAMPLE_TIME: - if (sampledata->nsamples++) - fprintf (sampledata->ostream, "\n"); - fprintf (sampledata->ostream, "\n"); - fprintf (sampledata->ostream, " \n", value.time / 60, value.time % 60); - break; - case DC_SAMPLE_DEPTH: - fprintf (sampledata->ostream, " %.2f\n", value.depth); - break; - case DC_SAMPLE_PRESSURE: - fprintf (sampledata->ostream, " %.2f\n", value.pressure.tank, value.pressure.value); - break; - case DC_SAMPLE_TEMPERATURE: - fprintf (sampledata->ostream, " %.2f\n", value.temperature); - break; - case DC_SAMPLE_EVENT: - if (value.event.type != SAMPLE_EVENT_GASCHANGE && value.event.type != SAMPLE_EVENT_GASCHANGE2) { - fprintf (sampledata->ostream, " %s\n", - value.event.type, value.event.time, value.event.flags, value.event.value, events[value.event.type]); - } - break; - case DC_SAMPLE_RBT: - fprintf (sampledata->ostream, " %u\n", value.rbt); - break; - case DC_SAMPLE_HEARTBEAT: - fprintf (sampledata->ostream, " %u\n", value.heartbeat); - break; - case DC_SAMPLE_BEARING: - fprintf (sampledata->ostream, " %u\n", value.bearing); - break; - case DC_SAMPLE_VENDOR: - fprintf (sampledata->ostream, " ", value.vendor.type, value.vendor.size); - for (unsigned int i = 0; i < value.vendor.size; ++i) - fprintf (sampledata->ostream, "%02X", ((unsigned char *) value.vendor.data)[i]); - fprintf (sampledata->ostream, "\n"); - break; - case DC_SAMPLE_SETPOINT: - fprintf (sampledata->ostream, " %.2f\n", value.setpoint); - break; - case DC_SAMPLE_PPO2: - fprintf (sampledata->ostream, " %.2f\n", value.ppo2); - break; - case DC_SAMPLE_CNS: - fprintf (sampledata->ostream, " %.1f\n", value.cns * 100.0); - break; - case DC_SAMPLE_DECO: - fprintf (sampledata->ostream, " %s\n", - value.deco.time, value.deco.depth, decostop[value.deco.type]); - break; - case DC_SAMPLE_GASMIX: - fprintf (sampledata->ostream, " %u\n", value.gasmix); - break; - default: - break; - } -} - -static dc_status_t -doparse (FILE *ostream, dc_device_t *device, const unsigned char data[], unsigned int size) -{ - dc_status_t rc = DC_STATUS_SUCCESS; - dc_parser_t *parser = NULL; - - // Create the parser. - message ("Creating the parser.\n"); - rc = dc_parser_new (&parser, device); - if (rc != DC_STATUS_SUCCESS) { - ERROR ("Error creating the parser."); - goto cleanup; - } - - // Register the data. - message ("Registering the data.\n"); - rc = dc_parser_set_data (parser, data, size); - if (rc != DC_STATUS_SUCCESS) { - ERROR ("Error registering the data."); - goto cleanup; - } - - // Parse the datetime. - message ("Parsing the datetime.\n"); - dc_datetime_t dt = {0}; - rc = dc_parser_get_datetime (parser, &dt); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - ERROR ("Error parsing the datetime."); - goto cleanup; - } - - fprintf (ostream, "%04i-%02i-%02i %02i:%02i:%02i\n", - dt.year, dt.month, dt.day, - dt.hour, dt.minute, dt.second); - - // Parse the divetime. - message ("Parsing the divetime.\n"); - unsigned int divetime = 0; - rc = dc_parser_get_field (parser, DC_FIELD_DIVETIME, 0, &divetime); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - ERROR ("Error parsing the divetime."); - goto cleanup; - } - - fprintf (ostream, "%02u:%02u\n", - divetime / 60, divetime % 60); - - // Parse the maxdepth. - message ("Parsing the maxdepth.\n"); - double maxdepth = 0.0; - rc = dc_parser_get_field (parser, DC_FIELD_MAXDEPTH, 0, &maxdepth); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - ERROR ("Error parsing the maxdepth."); - goto cleanup; - } - - fprintf (ostream, "%.2f\n", - maxdepth); - - // Parse the temperature. - message ("Parsing the temperature.\n"); - for (unsigned int i = 0; i < 3; ++i) { - dc_field_type_t fields[] = {DC_FIELD_TEMPERATURE_SURFACE, - DC_FIELD_TEMPERATURE_MINIMUM, - DC_FIELD_TEMPERATURE_MAXIMUM}; - const char *names[] = {"surface", "minimum", "maximum"}; - - double temperature = 0.0; - rc = dc_parser_get_field (parser, fields[i], 0, &temperature); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - ERROR ("Error parsing the temperature."); - goto cleanup; - } - - if (rc != DC_STATUS_UNSUPPORTED) { - fprintf (ostream, "%.1f\n", - names[i], temperature); - } - } - - // Parse the gas mixes. - message ("Parsing the gas mixes.\n"); - unsigned int ngases = 0; - rc = dc_parser_get_field (parser, DC_FIELD_GASMIX_COUNT, 0, &ngases); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - ERROR ("Error parsing the gas mix count."); - goto cleanup; - } - - for (unsigned int i = 0; i < ngases; ++i) { - dc_gasmix_t gasmix = {0}; - rc = dc_parser_get_field (parser, DC_FIELD_GASMIX, i, &gasmix); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - ERROR ("Error parsing the gas mix."); - goto cleanup; - } - - fprintf (ostream, - "\n" - " %.1f\n" - " %.1f\n" - " %.1f\n" - "\n", - gasmix.helium * 100.0, - gasmix.oxygen * 100.0, - gasmix.nitrogen * 100.0); - } - - // Parse the tanks. - message ("Parsing the tanks.\n"); - unsigned int ntanks = 0; - rc = dc_parser_get_field (parser, DC_FIELD_TANK_COUNT, 0, &ntanks); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - ERROR ("Error parsing the tank count."); - goto cleanup; - } - - for (unsigned int i = 0; i < ntanks; ++i) { - const char *names[] = {"none", "metric", "imperial"}; - - dc_tank_t tank = {0}; - rc = dc_parser_get_field (parser, DC_FIELD_TANK, i, &tank); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - ERROR ("Error parsing the tank."); - goto cleanup; - } - - fprintf (ostream, "\n"); - if (tank.gasmix != DC_GASMIX_UNKNOWN) { - fprintf (ostream, - " %u\n", - tank.gasmix); - } - if (tank.type != DC_TANKVOLUME_NONE) { - fprintf (ostream, - " %s\n" - " %.1f\n" - " %.2f\n", - names[tank.type], tank.volume, tank.workpressure); - } - fprintf (ostream, - " %.2f\n" - " %.2f\n" - "\n", - tank.beginpressure, tank.endpressure); - } - - // Parse the dive mode. - message ("Parsing the dive mode.\n"); - dc_divemode_t divemode = DC_DIVEMODE_OC; - rc = dc_parser_get_field (parser, DC_FIELD_DIVEMODE, 0, &divemode); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - ERROR ("Error parsing the dive mode."); - goto cleanup; - } - - if (rc != DC_STATUS_UNSUPPORTED) { - const char *names[] = {"freedive", "gauge", "oc", "cc"}; - fprintf (ostream, "%s\n", - names[divemode]); - } - - // Parse the salinity. - message ("Parsing the salinity.\n"); - dc_salinity_t salinity = {DC_WATER_FRESH, 0.0}; - rc = dc_parser_get_field (parser, DC_FIELD_SALINITY, 0, &salinity); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - ERROR ("Error parsing the salinity."); - goto cleanup; - } - - if (rc != DC_STATUS_UNSUPPORTED) { - fprintf (ostream, "%.1f\n", - salinity.type, salinity.density); - } - - // Parse the atmospheric pressure. - message ("Parsing the atmospheric pressure.\n"); - double atmospheric = 0.0; - rc = dc_parser_get_field (parser, DC_FIELD_ATMOSPHERIC, 0, &atmospheric); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - ERROR ("Error parsing the atmospheric pressure."); - goto cleanup; - } - - if (rc != DC_STATUS_UNSUPPORTED) { - fprintf (ostream, "%.5f\n", - atmospheric); - } - - // Initialize the sample data. - sample_data_t sampledata = {0}; - sampledata.nsamples = 0; - sampledata.ostream = ostream; - - // Parse the sample data. - message ("Parsing the sample data.\n"); - rc = dc_parser_samples_foreach (parser, sample_cb, &sampledata); - if (rc != DC_STATUS_SUCCESS) { - ERROR ("Error parsing the sample data."); - goto cleanup; - } - - if (sampledata.nsamples) - fprintf (ostream, "\n"); - -cleanup: - dc_parser_destroy (parser); - return rc; -} - static int dive_cb (const unsigned char *data, unsigned int size, const unsigned char *fingerprint, unsigned int fsize, void *userdata) { dive_data_t *divedata = (dive_data_t *) userdata; + dc_status_t rc = DC_STATUS_SUCCESS; + dc_parser_t *parser = NULL; divedata->number++; @@ -362,15 +76,32 @@ dive_cb (const unsigned char *data, unsigned int size, const unsigned char *fing *divedata->fingerprint = fp; } - fprintf (divedata->ostream, "\n%u\n%u\n", divedata->number, size); - for (unsigned int i = 0; i < fsize; ++i) - fprintf (divedata->ostream, "%02X", fingerprint[i]); - fprintf (divedata->ostream, "\n"); + // Create the parser. + message ("Creating the parser.\n"); + rc = dc_parser_new (&parser, divedata->device); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error creating the parser."); + goto cleanup; + } - doparse (divedata->ostream, divedata->device, data, size); + // Register the data. + message ("Registering the data.\n"); + rc = dc_parser_set_data (parser, data, size); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the data."); + goto cleanup; + } - fprintf (divedata->ostream, "\n"); + // Parse the dive data. + message ("Parsing the dive data.\n"); + rc = dctool_output_write (divedata->output, parser, data, size, fingerprint, fsize); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error parsing the dive data."); + goto cleanup; + } +cleanup: + dc_parser_destroy (parser); return 1; } @@ -421,7 +152,7 @@ event_cb (dc_device_t *device, dc_event_type_t event, const void *data, void *us } static dc_status_t -download (dc_context_t *context, dc_descriptor_t *descriptor, const char *devname, const char *cachedir, dc_buffer_t *fingerprint, FILE *ostream) +download (dc_context_t *context, dc_descriptor_t *descriptor, const char *devname, const char *cachedir, dc_buffer_t *fingerprint, dctool_output_t *output) { dc_status_t rc = DC_STATUS_SUCCESS; dc_device_t *device = NULL; @@ -476,11 +207,9 @@ download (dc_context_t *context, dc_descriptor_t *descriptor, const char *devnam // Initialize the dive data. dive_data_t divedata = {0}; divedata.device = device; - divedata.ostream = ostream; divedata.fingerprint = &ofingerprint; divedata.number = 0; - - fprintf (ostream, "\n"); + divedata.output = output; // Download the dives. message ("Downloading the dives.\n"); @@ -490,8 +219,6 @@ download (dc_context_t *context, dc_descriptor_t *descriptor, const char *devnam goto cleanup; } - fprintf (ostream, "\n"); - // Store the fingerprint data. if (cachedir && ofingerprint) { char filename[1024] = {0}; @@ -518,23 +245,25 @@ dctool_download_run (int argc, char *argv[], dc_context_t *context, dc_descripto int exitcode = EXIT_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS; dc_buffer_t *fingerprint = NULL; - FILE *ostream = NULL; + dctool_output_t *output = NULL; // Default option values. unsigned int help = 0; const char *fphex = NULL; const char *filename = NULL; const char *cachedir = NULL; + const char *format = "xml"; // Parse the command-line options. int opt = 0; - const char *optstring = "ho:p:c:"; + const char *optstring = "ho:p:c:f:"; #ifdef HAVE_GETOPT_LONG struct option options[] = { {"help", no_argument, 0, 'h'}, {"output", required_argument, 0, 'o'}, {"fingerprint", required_argument, 0, 'p'}, {"cache", required_argument, 0, 'c'}, + {"format", required_argument, 0, 'f'}, {0, 0, 0, 0 } }; while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { @@ -554,6 +283,9 @@ dctool_download_run (int argc, char *argv[], dc_context_t *context, dc_descripto case 'c': cachedir = optarg; break; + case 'f': + format = optarg; + break; default: return EXIT_FAILURE; } @@ -571,16 +303,24 @@ dctool_download_run (int argc, char *argv[], dc_context_t *context, dc_descripto // Convert the fingerprint to binary. fingerprint = dctool_convert_hex2bin (fphex); - // Open the output file. - ostream = fopen (filename, "w"); - if (ostream == NULL) { - message ("Failed to open the output file.\n"); + // Create the output. + if (strcasecmp(format, "raw") == 0) { + output = dctool_raw_output_new (filename); + } else if (strcasecmp(format, "xml") == 0) { + output = dctool_xml_output_new (filename); + } else { + message ("Unknown output format: %s\n", format); + exitcode = EXIT_FAILURE; + goto cleanup; + } + if (output == NULL) { + message ("Failed to create the output.\n"); exitcode = EXIT_FAILURE; goto cleanup; } // Download the dives. - status = download (context, descriptor, argv[0], cachedir, fingerprint, ostream); + status = download (context, descriptor, argv[0], cachedir, fingerprint, output); if (status != DC_STATUS_SUCCESS) { message ("ERROR: %s\n", dctool_errmsg (status)); exitcode = EXIT_FAILURE; @@ -588,7 +328,7 @@ dctool_download_run (int argc, char *argv[], dc_context_t *context, dc_descripto } cleanup: - if (ostream) fclose (ostream); + dctool_output_free (output); dc_buffer_free (fingerprint); return exitcode; } @@ -607,10 +347,30 @@ const dctool_command_t dctool_download = { " -o, --output Output filename\n" " -p, --fingerprint Fingerprint data (hexadecimal)\n" " -c, --cache Cache directory\n" + " -f, --format Output format\n" #else " -h Show help message\n" " -o Output filename\n" " -p Fingerprint data (hexadecimal)\n" " -c Cache directory\n" + " -f Output format\n" #endif + "\n" + "Supported output formats:\n" + "\n" + " XML (default)\n" + "\n" + " All dives are exported to a single xml file.\n" + "\n" + " RAW\n" + "\n" + " Each dive is exported to a raw (binary) file. To output multiple\n" + " files, the filename is interpreted as a template and should\n" + " contain one or more placeholders.\n" + "\n" + "Supported template placeholders:\n" + "\n" + " %f Fingerprint (hexadecimal format)\n" + " %n Number (4 digits)\n" + " %t Timestamp (basic ISO 8601 date/time format)\n" }; From 83e54d84a212298b73d9a4db701462c2ca71a27c Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 7 Feb 2016 21:29:27 +0100 Subject: [PATCH 44/45] Add support for the parse command. --- examples/Makefile.am | 1 + examples/dctool.c | 1 + examples/dctool.h | 1 + examples/dctool_parse.c | 304 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 307 insertions(+) create mode 100644 examples/dctool_parse.c diff --git a/examples/Makefile.am b/examples/Makefile.am index 4c1aa05..e830769 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -14,6 +14,7 @@ dctool_SOURCES = \ dctool_list.c \ dctool_download.c \ dctool_dump.c \ + dctool_parse.c \ dctool_read.c \ dctool_write.c \ dctool_fwupdate.c \ diff --git a/examples/dctool.c b/examples/dctool.c index a317980..b1c9e0f 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -60,6 +60,7 @@ static const dctool_command_t *g_commands[] = { &dctool_list, &dctool_download, &dctool_dump, + &dctool_parse, &dctool_read, &dctool_write, &dctool_fwupdate, diff --git a/examples/dctool.h b/examples/dctool.h index a0e09d7..cc6a393 100644 --- a/examples/dctool.h +++ b/examples/dctool.h @@ -47,6 +47,7 @@ extern const dctool_command_t dctool_version; extern const dctool_command_t dctool_list; extern const dctool_command_t dctool_download; extern const dctool_command_t dctool_dump; +extern const dctool_command_t dctool_parse; extern const dctool_command_t dctool_read; extern const dctool_command_t dctool_write; extern const dctool_command_t dctool_fwupdate; diff --git a/examples/dctool_parse.c b/examples/dctool_parse.c new file mode 100644 index 0000000..ef05aa4 --- /dev/null +++ b/examples/dctool_parse.c @@ -0,0 +1,304 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dctool.h" +#include "output.h" +#include "common.h" +#include "utils.h" + +#define REACTPROWHITE 0x4354 + +static dc_status_t +parse (dc_buffer_t *buffer, dc_context_t *context, dc_descriptor_t *descriptor, unsigned int devtime, dc_ticks_t systime, dctool_output_t *output) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + dc_parser_t *parser = NULL; + dc_family_t family = dc_descriptor_get_type (descriptor); + unsigned int model = dc_descriptor_get_model (descriptor); + unsigned char *data = dc_buffer_get_data (buffer); + unsigned int size = dc_buffer_get_size (buffer); + + // Create the parser. + message ("Creating the parser.\n"); + switch (family) { + case DC_FAMILY_SUUNTO_SOLUTION: + rc = suunto_solution_parser_create (&parser, context); + break; + case DC_FAMILY_SUUNTO_EON: + rc = suunto_eon_parser_create (&parser, context, 0); + break; + case DC_FAMILY_SUUNTO_VYPER: + if (model == 0x01) + rc = suunto_eon_parser_create (&parser, context, 1); + else + rc = suunto_vyper_parser_create (&parser, context); + break; + case DC_FAMILY_SUUNTO_VYPER2: + case DC_FAMILY_SUUNTO_D9: + rc = suunto_d9_parser_create (&parser, context, model); + break; + case DC_FAMILY_SUUNTO_EONSTEEL: + rc = suunto_eonsteel_parser_create(&parser, context, model); + break; + case DC_FAMILY_UWATEC_ALADIN: + case DC_FAMILY_UWATEC_MEMOMOUSE: + rc = uwatec_memomouse_parser_create (&parser, context, devtime, systime); + break; + case DC_FAMILY_UWATEC_SMART: + case DC_FAMILY_UWATEC_MERIDIAN: + rc = uwatec_smart_parser_create (&parser, context, model, devtime, systime); + break; + case DC_FAMILY_REEFNET_SENSUS: + rc = reefnet_sensus_parser_create (&parser, context, devtime, systime); + break; + case DC_FAMILY_REEFNET_SENSUSPRO: + rc = reefnet_sensuspro_parser_create (&parser, context, devtime, systime); + break; + case DC_FAMILY_REEFNET_SENSUSULTRA: + rc = reefnet_sensusultra_parser_create (&parser, context, devtime, systime); + break; + case DC_FAMILY_OCEANIC_VTPRO: + rc = oceanic_vtpro_parser_create (&parser, context); + break; + case DC_FAMILY_OCEANIC_VEO250: + rc = oceanic_veo250_parser_create (&parser, context, model); + break; + case DC_FAMILY_OCEANIC_ATOM2: + if (model == REACTPROWHITE) + rc = oceanic_veo250_parser_create (&parser, context, model); + else + rc = oceanic_atom2_parser_create (&parser, context, model); + break; + case DC_FAMILY_MARES_NEMO: + case DC_FAMILY_MARES_PUCK: + rc = mares_nemo_parser_create (&parser, context, model); + break; + case DC_FAMILY_MARES_DARWIN: + rc = mares_darwin_parser_create (&parser, context, model); + break; + case DC_FAMILY_MARES_ICONHD: + rc = mares_iconhd_parser_create (&parser, context, model); + break; + case DC_FAMILY_HW_OSTC: + rc = hw_ostc_parser_create (&parser, context, 0); + break; + case DC_FAMILY_HW_FROG: + case DC_FAMILY_HW_OSTC3: + rc = hw_ostc_parser_create (&parser, context, 1); + break; + case DC_FAMILY_CRESSI_EDY: + case DC_FAMILY_ZEAGLE_N2ITION3: + rc = cressi_edy_parser_create (&parser, context, model); + break; + case DC_FAMILY_CRESSI_LEONARDO: + rc = cressi_leonardo_parser_create (&parser, context); + break; + case DC_FAMILY_ATOMICS_COBALT: + rc = atomics_cobalt_parser_create (&parser, context); + break; + case DC_FAMILY_SHEARWATER_PREDATOR: + rc = shearwater_predator_parser_create (&parser, context); + break; + case DC_FAMILY_SHEARWATER_PETREL: + rc = shearwater_petrel_parser_create (&parser, context); + break; + case DC_FAMILY_DIVERITE_NITEKQ: + rc = diverite_nitekq_parser_create (&parser, context); + break; + case DC_FAMILY_CITIZEN_AQUALAND: + rc = citizen_aqualand_parser_create (&parser, context); + break; + case DC_FAMILY_DIVESYSTEM_IDIVE: + rc = divesystem_idive_parser_create2 (&parser, context, model); + break; + default: + rc = DC_STATUS_INVALIDARGS; + break; + } + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error creating the parser."); + goto cleanup; + } + + // Register the data. + message ("Registering the data.\n"); + rc = dc_parser_set_data (parser, data, size); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the data."); + goto cleanup; + } + + // Parse the dive data. + message ("Parsing the dive data.\n"); + rc = dctool_output_write (output, parser, data, size, NULL, 0); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error parsing the dive data."); + goto cleanup; + } + +cleanup: + dc_parser_destroy (parser); + return rc; +} + +static int +dctool_parse_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t *descriptor) +{ + // Default values. + int exitcode = EXIT_SUCCESS; + dc_status_t status = DC_STATUS_SUCCESS; + dc_buffer_t *buffer = NULL; + dctool_output_t *output = NULL; + + // Default option values. + unsigned int help = 0; + const char *filename = NULL; + unsigned int devtime = 0; + dc_ticks_t systime = 0; + + // Parse the command-line options. + int opt = 0; + const char *optstring = "ho:d:s:"; +#ifdef HAVE_GETOPT_LONG + struct option options[] = { + {"help", no_argument, 0, 'h'}, + {"output", required_argument, 0, 'o'}, + {"devtime", required_argument, 0, 'd'}, + {"systime", required_argument, 0, 's'}, + {0, 0, 0, 0 } + }; + while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { +#else + while ((opt = getopt (argc, argv, optstring)) != -1) { +#endif + switch (opt) { + case 'h': + help = 1; + break; + case 'o': + filename = optarg; + break; + case 'd': + devtime = strtoul (optarg, NULL, 0); + break; + case 's': + systime = strtoll (optarg, NULL, 0); + break; + default: + return EXIT_FAILURE; + } + } + + argc -= optind; + argv += optind; + + // Show help message. + if (help) { + dctool_command_showhelp (&dctool_parse); + return EXIT_SUCCESS; + } + + // Create the output. + output = dctool_xml_output_new (filename); + if (output == NULL) { + message ("Failed to create the output.\n"); + exitcode = EXIT_FAILURE; + goto cleanup; + } + + for (unsigned int i = 0; i < argc; ++i) { + // Read the input file. + buffer = dctool_file_read (argv[i]); + if (buffer == NULL) { + message ("Failed to open the input file.\n"); + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Parse the dive. + status = parse (buffer, context, descriptor, devtime, systime, output); + if (status != DC_STATUS_SUCCESS) { + message ("ERROR: %s\n", dctool_errmsg (status)); + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Cleanup. + dc_buffer_free (buffer); + buffer = NULL; + } + +cleanup: + dc_buffer_free (buffer); + dctool_output_free (output); + return exitcode; +} + +const dctool_command_t dctool_parse = { + dctool_parse_run, + DCTOOL_CONFIG_DESCRIPTOR, + "parse", + "Parse previously downloaded dives", + "Usage:\n" + " dctool parse [options] \n" + "\n" + "Options:\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help Show help message\n" + " -o, --output Output filename\n" + " -d, --devtime Device time\n" + " -s, --systime System time\n" +#else + " -h Show help message\n" + " -o Output filename\n" + " -d Device time\n" + " -s System time\n" +#endif +}; From 90cf480c259be0537892df4faafd70b5616f4035 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 23 Feb 2016 22:57:52 +0100 Subject: [PATCH 45/45] Fix the OSTC3 missing initial gas mix detection. For the OSTC3 compatible devices, a missing initial gas mix (e.g. no gas marked as the first gas) leaves the initial gas mix index at its default value of zero. This is different from the OSTC2 compatible devices, where a missing initial gas is stored as the value 0xFF. By initializing the index with the value 0xFF, the existing detection works for both variants. --- src/hw_ostc_parser.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index abc42ba..b6a6989 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -33,6 +33,8 @@ #define MAXCONFIG 7 #define NGASMIXES 15 +#define UNDEFINED 0xFF + #define ALL 0 #define FIXED 1 #define MANUAL 2 @@ -211,7 +213,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) } // Get all the gas mixes, and the index of the inital mix. - unsigned int initial = 0; + unsigned int initial = UNDEFINED; unsigned int ngasmixes = 0; hw_ostc_gasmix_t gasmix[NGASMIXES] = {{0}}; if (version == 0x22) { @@ -227,7 +229,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) gasmix[i].oxygen = data[28 + 4 * i + 0]; gasmix[i].helium = data[28 + 4 * i + 1]; // Find the first gas marked as the initial gas. - if (!initial && data[28 + 4 * i + 3] == 1) { + if (initial == UNDEFINED && data[28 + 4 * i + 3] == 1) { initial = i + 1; /* One based index! */ } } @@ -239,7 +241,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) gasmix[i].helium = data[19 + 2 * i + 1]; } } - if (initial != 0xFF) { + if (initial != UNDEFINED) { if (initial < 1 || initial > ngasmixes) { ERROR(abstract->context, "Invalid initial gas mix."); return DC_STATUS_DATAFORMAT; @@ -604,7 +606,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call if (callback) callback (DC_SAMPLE_TIME, sample, userdata); // Initial gas mix. - if (time == samplerate && parser->initial != 0xFF) { + if (time == samplerate && parser->initial != UNDEFINED) { sample.gasmix = parser->initial; if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata); #ifdef ENABLE_DEPRECATED