diff --git a/configure.ac b/configure.ac index 7942444..d20179d 100644 --- a/configure.ac +++ b/configure.ac @@ -112,10 +112,16 @@ 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]) +AC_CHECK_HEADERS([sys/param.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]) +AC_CHECK_FUNCS([getopt_long]) # Versioning. AC_SUBST([DC_VERSION],[dc_version]) diff --git a/examples/Makefile.am b/examples/Makefile.am index d77db45..e830769 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -2,12 +2,26 @@ 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 = \ + common.h \ + common.c \ + dctool.h \ + dctool.c \ + dctool_help.c \ + dctool_version.c \ + dctool_list.c \ + dctool_download.c \ + dctool_dump.c \ + dctool_parse.c \ + dctool_read.c \ + dctool_write.c \ + dctool_fwupdate.c \ + output.h \ + output-private.h \ + output.c \ + output_xml.c \ + output_raw.c \ + utils.h \ + utils.c diff --git a/examples/common.c b/examples/common.c index f69e7e4..fb7f73e 100644 --- a/examples/common.c +++ b/examples/common.c @@ -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,13 +19,69 @@ * MA 02110-1301 USA */ +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + #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 { + 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}, +}; + const char * -errmsg (dc_status_t rc) +dctool_errmsg (dc_status_t status) { - switch (rc) { + switch (status) { case DC_STATUS_SUCCESS: return "Success"; case DC_STATUS_UNSUPPORTED: @@ -53,14 +109,220 @@ 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) +dc_family_t +dctool_family_type (const char *name) { - const char *loglevels[] = {"NONE", "ERROR", "WARNING", "INFO", "DEBUG", "ALL"}; + 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; + } - 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); + 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; +} + +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) +{ + 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; +} + +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) +{ + 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 4c23f1b..f17d578 100644 --- a/examples/common.h +++ b/examples/common.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,42 @@ * MA 02110-1301 USA */ -#ifndef EXAMPLES_COMMON_H -#define EXAMPLES_COMMON_H +#ifndef DCTOOL_COMMON_H +#define DCTOOL_COMMON_H -#include #include +#include +#include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ const char * -errmsg (dc_status_t rc); +dctool_errmsg (dc_status_t status); + +dc_family_t +dctool_family_type (const char *name); + +const char * +dctool_family_name (dc_family_t type); void -logfunc (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *msg, void *userdata); +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); + +dc_buffer_t * +dctool_convert_hex2bin (const char *str); + +void +dctool_file_write (const char *filename, dc_buffer_t *buffer); + +dc_buffer_t * +dctool_file_read (const char *filename); #ifdef __cplusplus } #endif /* __cplusplus */ -#endif /* EXAMPLES_COMMON_H */ +#endif /* DCTOOL_COMMON_H */ diff --git a/examples/dctool.c b/examples/dctool.c new file mode 100644 index 0000000..b1c9e0f --- /dev/null +++ b/examples/dctool.c @@ -0,0 +1,306 @@ +/* + * 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 +#include +#ifdef HAVE_GETOPT_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#include +#include + +#include "common.h" +#include "dctool.h" +#include "utils.h" + +#if defined(__GLIBC__) || defined(__MINGW32__) +#define RESET 0 +#else +#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, + &dctool_list, + &dctool_download, + &dctool_dump, + &dctool_parse, + &dctool_read, + &dctool_write, + &dctool_fwupdate, + NULL +}; + +static volatile sig_atomic_t g_cancel = 0; + +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]; +} + +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) +{ + 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) +{ + 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; + 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 "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'}, + {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 '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; + case 'q': + loglevel = DC_LOGLEVEL_NONE; + break; + case 'v': + loglevel++; + break; + default: + return EXIT_FAILURE; + } + } + + // Skip the processed arguments. + 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}; + if (help || argv[0] == NULL) { + if (argv[0]) { + argv_help[1] = argv[0]; + argv = argv_help; + argc = 2; + } else { + argv = argv_help; + argc = 1; + } + } + + // 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; + } + + // Setup the cancel signal handler. + signal (SIGINT, sighandler); + + // 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); + + 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, 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 new file mode 100644 index 0000000..cc6a393 --- /dev/null +++ b/examples/dctool.h @@ -0,0 +1,68 @@ +/* + * 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_H +#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, dc_descriptor_t *descriptor); + unsigned int config; + const char *name; + const char *description; + const char *usage; +} 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; +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; + +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); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* DCTOOL_H */ diff --git a/examples/dctool_download.c b/examples/dctool_download.c new file mode 100644 index 0000000..4baa333 --- /dev/null +++ b/examples/dctool_download.c @@ -0,0 +1,376 @@ +/* + * 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 "output.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 { + dc_device_t *device; + dc_buffer_t **fingerprint; + unsigned int number; + dctool_output_t *output; +} dive_data_t; + +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++; + + 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; + } + + // 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; + } + + // 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 (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; +} + +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, dctool_output_t *output) +{ + 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.fingerprint = &ofingerprint; + divedata.number = 0; + divedata.output = output; + + // 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; + } + + // 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; + 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: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) { +#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; + case 'f': + format = 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); + + // 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, output); + if (status != DC_STATUS_SUCCESS) { + message ("ERROR: %s\n", dctool_errmsg (status)); + exitcode = EXIT_FAILURE; + goto cleanup; + } + +cleanup: + dctool_output_free (output); + 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" + " -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" +}; 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 +}; 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 +}; 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 +}; 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 +}; 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 +}; 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_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 +}; 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 +}; 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/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..0912de2 --- /dev/null +++ b/examples/output.h @@ -0,0 +1,49 @@ +/* + * 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; + +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); + +dc_status_t +dctool_output_free (dctool_output_t *output); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DCTOOL_OUTPUT_H */ 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; +} 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; +} diff --git a/examples/universal.c b/examples/universal.c deleted file mode 100644 index 1d61ef8..0000000 --- a/examples/universal.c +++ /dev/null @@ -1,980 +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_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); - } 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; - 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; -} 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); 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/include/libdivecomputer/parser.h b/include/libdivecomputer/parser.h index dbd9d2d..921efdc 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 { @@ -78,7 +79,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, @@ -92,9 +93,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 */ @@ -220,6 +219,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/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 0f3ff37..35951bf 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) $(HIDAPI_CFLAGS) +AM_CFLAGS = $(LIBUSB_CFLAGS) $(HIDAPI_CFLAGS) -DENABLE_DEPRECATED lib_LTLIBRARIES = libdivecomputer.la @@ -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/atomics_cobalt.c b/src/atomics_cobalt.c index aec412d..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 */ @@ -82,20 +83,22 @@ 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 *) 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; @@ -105,39 +108,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: + dc_device_deallocate ((dc_device_t *) device); + return status; #else return DC_STATUS_UNSUPPORTED; #endif @@ -155,9 +160,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 ab6ec6a..11c7ee7 100644 --- a/src/atomics_cobalt_parser.c +++ b/src/atomics_cobalt_parser.c @@ -54,34 +54,33 @@ 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 = { + sizeof(atomics_cobalt_parser_t), DC_FAMILY_ATOMICS_COBALT, atomics_cobalt_parser_set_data, /* set_data */ 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 */ }; 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; @@ -92,16 +91,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) { @@ -341,6 +330,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; @@ -348,6 +340,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/citizen_aqualand.c b/src/citizen_aqualand.c index dc291b4..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 */ @@ -63,19 +64,19 @@ 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 *) 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)); @@ -84,25 +85,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,24 +111,27 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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/citizen_aqualand_parser.c b/src/citizen_aqualand_parser.c index e9c2659..988375b 100644 --- a/src/citizen_aqualand_parser.c +++ b/src/citizen_aqualand_parser.c @@ -40,50 +40,39 @@ 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 = { + sizeof(citizen_aqualand_parser_t), DC_FAMILY_CITIZEN_AQUALAND, citizen_aqualand_parser_set_data, /* set_data */ 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 */ }; 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; } -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/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 2a7b271..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 */ @@ -236,19 +237,19 @@ 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 *) 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; @@ -259,34 +260,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 +306,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,12 +317,19 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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. @@ -333,14 +337,10 @@ 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_edy_parser.c b/src/cressi_edy_parser.c index 195eb41..06296f7 100644 --- a/src/cressi_edy_parser.c +++ b/src/cressi_edy_parser.c @@ -43,15 +43,15 @@ 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 = { + sizeof(cressi_edy_parser_t), DC_FAMILY_CRESSI_EDY, cressi_edy_parser_set_data, /* set_data */ 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 */ }; @@ -73,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; @@ -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) { @@ -227,11 +216,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/cressi_leonardo.c b/src/cressi_leonardo.c index 2d6d177..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 */ @@ -74,19 +75,19 @@ 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 *) 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)); @@ -95,34 +96,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,23 +129,26 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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/cressi_leonardo_parser.c b/src/cressi_leonardo_parser.c index b01a37a..d9ed79c 100644 --- a/src/cressi_leonardo_parser.c +++ b/src/cressi_leonardo_parser.c @@ -41,50 +41,39 @@ 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 = { + sizeof(cressi_leonardo_parser_t), DC_FAMILY_CRESSI_EDY, cressi_leonardo_parser_set_data, /* set_data */ 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 */ }; 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; } -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/descriptor.c b/src/descriptor.c index 18c8d77..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}, @@ -254,6 +255,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-private.h b/src/device-private.h index 8e183fb..dcf0b96 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 */ @@ -55,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); @@ -73,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 fd6fe9b..554a169 100644 --- a/src/device.c +++ b/src/device.c @@ -41,10 +41,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; @@ -58,6 +69,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 @@ -164,7 +183,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; @@ -355,17 +374,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); + } + + dc_device_deallocate (device); + + return status; } diff --git a/src/diverite_nitekq.c b/src/diverite_nitekq.c index 6ca5356..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 */ @@ -149,19 +150,19 @@ 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 *) 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)); @@ -170,25 +171,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,24 +195,28 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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. @@ -221,14 +224,10 @@ 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/diverite_nitekq_parser.c b/src/diverite_nitekq_parser.c index deba81b..460dcbf 100644 --- a/src/diverite_nitekq_parser.c +++ b/src/diverite_nitekq_parser.c @@ -52,34 +52,33 @@ 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 = { + sizeof(diverite_nitekq_parser_t), DC_FAMILY_DIVERITE_NITEKQ, diverite_nitekq_parser_set_data, /* set_data */ 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 */ }; 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; @@ -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) { @@ -270,11 +259,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.c b/src/divesystem_idive.c index eecfb5a..e48e47b 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); @@ -69,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 */ @@ -78,50 +87,69 @@ 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) +{ + 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 *) 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)); + device->model = model; // Open the device. 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. @@ -131,24 +159,27 @@ divesystem_idive_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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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; } @@ -334,39 +365,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 +421,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 +454,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..64454a8 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; @@ -53,35 +62,48 @@ 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 = { + sizeof(divesystem_idive_parser_t), DC_FAMILY_DIVESYSTEM_IDIVE, divesystem_idive_parser_set_data, /* set_data */ 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 */ }; 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) +{ + 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; + 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; @@ -97,16 +119,6 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context) } -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) { @@ -129,7 +141,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 +161,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 +215,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). @@ -250,11 +264,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; } @@ -279,7 +297,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/hw_frog.c b/src/hw_frog.c index 43bc307..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 */ @@ -202,19 +203,19 @@ 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 *) 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)); @@ -223,25 +224,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,44 +248,44 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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 d994d38..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 */ @@ -125,19 +126,19 @@ 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 *) 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)); @@ -146,25 +147,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,24 +173,27 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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 c7dfb03..26bbefc 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -124,6 +124,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 */ @@ -276,19 +277,19 @@ 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 *) 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->serial = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); @@ -297,25 +298,23 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name int rc = dc_serial_native_open (&device->serial, context, name); if (rc != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - free (device); - return rc; + status = DC_STATUS_IO; + goto error_free; } // Set the serial communication protocol (115200 8N1). rc = serial_configure (device->serial->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - device->serial->ops->close (device->serial->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->serial->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - device->serial->ops->close (device->serial->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -327,12 +326,20 @@ 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: + device->serial->ops->close (device->serial->port); +error_free: + dc_device_deallocate ((dc_device_t *) device); + return status; } dc_status_t hw_ostc3_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial_t *serial) { + dc_status_t status = DC_STATUS_SUCCESS; + if (out == NULL || serial == NULL || serial->port == NULL) return DC_STATUS_INVALIDARGS; @@ -343,9 +350,6 @@ hw_ostc3_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial return DC_STATUS_NOMEMORY; } - // Initialize the base class. - device_init (&device->base, context, &hw_ostc3_device_vtable); - // Set the default values. memset (device->fingerprint, 0, sizeof (device->fingerprint)); @@ -357,18 +361,17 @@ hw_ostc3_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial int rc = serial_configure (device->serial->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - device->serial->ops->close (device->serial->port); free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } } // Set the timeout for receiving data (3000ms). if (device->serial->ops->set_timeout (device->serial->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - device->serial->ops->close (device->serial->port); - free (device); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -380,6 +383,12 @@ hw_ostc3_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; + +error_close: + device->serial->ops->close (device->serial->port); +error_free: + dc_device_deallocate ((dc_device_t *) device); + return status; } @@ -434,7 +443,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; @@ -477,6 +486,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; @@ -486,21 +496,16 @@ hw_ostc3_device_close (dc_device_t *abstract) if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); device->serial->ops->close (device->serial->port); - free (device); - return rc; + dc_status_set_error(&status, rc); } } // Close the device. if (device->serial->ops->close (device->serial->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; } @@ -1065,7 +1070,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; diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index 1250e1c..a3b0e68 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -39,6 +39,8 @@ #define MAXCONFIG 7 #define NGASMIXES 15 +#define UNDEFINED 0xFF + #define ALL 0 #define FIXED 1 #define MANUAL 2 @@ -115,15 +117,15 @@ 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 = { + sizeof(hw_ostc_parser_t), DC_FAMILY_HW_OSTC, hw_ostc_parser_set_data, /* set_data */ 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 = { @@ -247,7 +249,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) { @@ -263,7 +265,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! */ } } @@ -275,7 +277,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; @@ -303,19 +305,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 serial, 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; @@ -337,16 +338,6 @@ hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int se } -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) { @@ -707,7 +698,10 @@ 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 unsigned int idx = parser->initial; unsigned int o2 = parser->gasmix[idx].oxygen; unsigned int he = parser->gasmix[idx].helium; @@ -716,6 +710,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). @@ -800,11 +795,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; } @@ -821,6 +821,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; @@ -828,6 +831,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--; } @@ -851,11 +855,29 @@ 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.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 = data[offset] | (data[offset + 1] << 16); + sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif offset += 2; length -= 2; } @@ -941,11 +963,29 @@ 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.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 = data[offset] | (data[offset + 1] << 16); + sample.event.value = o2 | (he << 16); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); +#endif offset += 2; length -= 2; } diff --git a/src/irda.c b/src/irda.c index b15d09f..57b5076 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 @@ -75,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) } @@ -90,10 +98,10 @@ 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); - free (device); - return -1; + int rc = WSAStartup (wVersionRequested, &wsaData); + if (rc != 0) { + SYSERROR (context, rc); + goto error_free; } // Confirm that the winsock dll supports version 2.2. @@ -102,36 +110,36 @@ 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 // 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); -#ifdef _WIN32 - WSACleanup (); -#endif - free (device); - return -1; + if (device->fd == S_INVALID) { + SYSERROR (context, S_ERRNO); + goto error_wsacleanup; } *out = device; return 0; + +error_wsacleanup: +#ifdef _WIN32 + WSACleanup (); +error_free: +#endif + free (device); + return -1; } int irda_socket_close (irda_t *device) { + int errcode = 0; + if (device == NULL) return -1; @@ -139,32 +147,23 @@ 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); -#ifdef _WIN32 - WSACleanup (); -#endif - free (device); - return -1; + 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); - free (device); - return -1; + SYSERROR (device->context, S_ERRNO); + errcode = -1; } #endif // Free memory. free (device); - return 0; + return errcode; } @@ -222,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. } } @@ -250,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; @@ -321,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; } @@ -353,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; } @@ -369,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; } @@ -402,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. @@ -410,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. @@ -435,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. } diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index 0cef199..64f7f3e 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 @@ -178,3 +179,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/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 957e7d9..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 */ @@ -96,18 +97,21 @@ 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 *) 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)); @@ -121,34 +125,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,23 +163,26 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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_darwin_parser.c b/src/mares_darwin_parser.c index 5de4c4b..42cccb4 100644 --- a/src/mares_darwin_parser.c +++ b/src/mares_darwin_parser.c @@ -47,34 +47,33 @@ 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 = { + sizeof(mares_darwin_parser_t), DC_FAMILY_MARES_DARWIN, mares_darwin_parser_set_data, /* set_data */ 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 */ }; 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) { @@ -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 02a13ad..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 */ @@ -214,19 +215,19 @@ 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 *) 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; @@ -239,25 +240,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 +264,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 +273,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,24 +310,27 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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_iconhd_parser.c b/src/mares_iconhd_parser.c index 8992f64..8789a71 100644 --- a/src/mares_iconhd_parser.c +++ b/src/mares_iconhd_parser.c @@ -60,15 +60,15 @@ 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 = { + sizeof(mares_iconhd_parser_t), DC_FAMILY_MARES_ICONHD, mares_iconhd_parser_set_data, /* set_data */ 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 @@ -198,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; @@ -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) { @@ -510,10 +499,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/mares_nemo.c b/src/mares_nemo.c index e479b02..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 */ @@ -90,19 +91,19 @@ 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 *) 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)); @@ -111,34 +112,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,24 +145,27 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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_nemo_parser.c b/src/mares_nemo_parser.c index b997ae4..33e5916 100644 --- a/src/mares_nemo_parser.c +++ b/src/mares_nemo_parser.c @@ -63,34 +63,33 @@ 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 = { + sizeof(mares_nemo_parser_t), DC_FAMILY_MARES_NEMO, mares_nemo_parser_set_data, /* set_data */ 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 */ }; 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) @@ -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 361a753..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 */ @@ -88,18 +89,21 @@ 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 *) 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; @@ -109,34 +113,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 +145,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,24 +170,27 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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 98a8273..67fa45a 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 */ @@ -85,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[] = { @@ -196,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 */ @@ -520,20 +522,22 @@ 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 *) 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; @@ -546,8 +550,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 +564,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 +588,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,12 +641,19 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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. @@ -654,14 +661,10 @@ 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_atom2_parser.c b/src/oceanic_atom2_parser.c index 487a744..5de8c7c 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -72,9 +72,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 @@ -110,34 +111,33 @@ 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 = { + sizeof(oceanic_atom2_parser_t), DC_FAMILY_OCEANIC_ATOM2, oceanic_atom2_parser_set_data, /* set_data */ 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 */ }; dc_status_t oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model, unsigned int serial) { + 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; @@ -157,10 +157,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; - } else if (model == F11) { + 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; } @@ -184,16 +184,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) { @@ -222,7 +212,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) @@ -255,6 +246,12 @@ 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: + 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; @@ -265,14 +262,15 @@ 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); 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]); @@ -298,11 +296,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; @@ -377,7 +371,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) { @@ -481,13 +476,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) - *((unsigned int *) value) = bcd2dec (data[2]) + bcd2dec (data[3]) * 60 + bcd2dec (data[1]) * 3600; + if (parser->model == F10 || parser->model == F11A || + parser->model == F11B) + *((unsigned int *) value) = bcd2dec (data[2]) + bcd2dec (data[3]) * 60; else *((unsigned int *) value) = parser->divetime; break; case DC_FIELD_MAXDEPTH: - if (parser->model == F10 || parser->model == 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; @@ -563,6 +560,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) @@ -581,11 +579,36 @@ 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; 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; @@ -636,7 +659,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; @@ -658,7 +682,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) @@ -796,6 +820,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; @@ -803,6 +830,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/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 c7828e4..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 */ @@ -221,18 +222,21 @@ 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 *) 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; @@ -246,34 +250,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 +284,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,20 +297,25 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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. @@ -319,14 +323,10 @@ 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_veo250_parser.c b/src/oceanic_veo250_parser.c index 36eeeb4..a300af8 100644 --- a/src/oceanic_veo250_parser.c +++ b/src/oceanic_veo250_parser.c @@ -51,34 +51,33 @@ 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 = { + sizeof(oceanic_veo250_parser_t), DC_FAMILY_OCEANIC_VEO250, oceanic_veo250_parser_set_data, /* set_data */ 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 */ }; 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; @@ -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 5696045..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 */ @@ -254,18 +255,21 @@ 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 *) 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; @@ -277,34 +281,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 +315,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 +325,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 +333,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,12 +346,19 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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 +366,10 @@ 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/oceanic_vtpro_parser.c b/src/oceanic_vtpro_parser.c index f7d2be5..d2d7919 100644 --- a/src/oceanic_vtpro_parser.c +++ b/src/oceanic_vtpro_parser.c @@ -45,34 +45,33 @@ 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 = { + sizeof(oceanic_vtpro_parser_t), DC_FAMILY_OCEANIC_VTPRO, oceanic_vtpro_parser_set_data, /* set_data */ 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 */ }; 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; @@ -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-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 66bb80a..f944206 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" @@ -140,7 +142,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; @@ -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) @@ -239,13 +261,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); + dc_parser_deallocate (parser); + + return status; } diff --git a/src/reefnet_sensus.c b/src/reefnet_sensus.c index 6504342..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 */ @@ -89,19 +90,19 @@ 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 *) 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; @@ -114,25 +115,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,12 +140,19 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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 @@ -156,14 +162,10 @@ 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_sensus_parser.c b/src/reefnet_sensus_parser.c index 9b5de72..ba4b7de 100644 --- a/src/reefnet_sensus_parser.c +++ b/src/reefnet_sensus_parser.c @@ -52,34 +52,33 @@ 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 = { + sizeof(reefnet_sensus_parser_t), DC_FAMILY_REEFNET_SENSUS, reefnet_sensus_parser_set_data, /* set_data */ 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 */ }; 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; @@ -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 b462f55..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 */ @@ -68,19 +69,19 @@ 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 *) 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; @@ -92,25 +93,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,24 +118,27 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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_sensuspro_parser.c b/src/reefnet_sensuspro_parser.c index 0f3af95..70decf8 100644 --- a/src/reefnet_sensuspro_parser.c +++ b/src/reefnet_sensuspro_parser.c @@ -51,34 +51,33 @@ 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 = { + sizeof(reefnet_sensuspro_parser_t), DC_FAMILY_REEFNET_SENSUSPRO, reefnet_sensuspro_parser_set_data, /* set_data */ 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 */ }; 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; @@ -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 6405830..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 */ @@ -77,19 +78,19 @@ 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 *) 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; @@ -101,25 +102,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,24 +127,27 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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/reefnet_sensusultra_parser.c b/src/reefnet_sensusultra_parser.c index 1d85b06..d44edfe 100644 --- a/src/reefnet_sensusultra_parser.c +++ b/src/reefnet_sensusultra_parser.c @@ -51,34 +51,33 @@ 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 = { + sizeof(reefnet_sensusultra_parser_t), DC_FAMILY_REEFNET_SENSUSULTRA, reefnet_sensusultra_parser_set_data, /* set_data */ 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 */ }; 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; @@ -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/serial_posix.c b/src/serial_posix.c index e9b7295..7cc83b6 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) } @@ -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; } // @@ -194,15 +195,15 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) 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 @@ -213,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 9d5572c..56c3866 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; } // @@ -178,6 +181,8 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) int serial_close (serial_t *device) { + int errcode = 0; + if (device == NULL) return 0; @@ -185,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/shearwater_common.c b/src/shearwater_common.c index 68a4209..a370c47 100644 --- a/src/shearwater_common.c +++ b/src/shearwater_common.c @@ -41,6 +41,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 = dc_serial_native_open (&device->serial, context, name); if (rc != DC_STATUS_SUCCESS) { @@ -52,15 +54,15 @@ shearwater_common_open (shearwater_common_device_t *device, dc_context_t *contex rc = serial_configure (device->serial->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); - device->serial->ops->close (device->serial->port); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Set the timeout for receiving data (3000ms). if (serial_set_timeout (device->serial->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); - device->serial->ops->close (device->serial->port); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -68,12 +70,18 @@ shearwater_common_open (shearwater_common_device_t *device, dc_context_t *contex device->serial->ops->flush (device->serial->port, SERIAL_QUEUE_BOTH); return DC_STATUS_SUCCESS; + +error_close: + device->serial->ops->close (device->serial->port); + return status; } dc_status_t shearwater_common_custom_open (shearwater_common_device_t *device, dc_context_t *context, dc_serial_t *serial) { + dc_status_t status = DC_STATUS_SUCCESS; + // Set the serial reference device->serial = serial; @@ -91,7 +99,8 @@ shearwater_common_custom_open (shearwater_common_device_t *device, dc_context_t if (device->serial->ops->set_timeout (device->serial->port, 3000) == -1) { ERROR (context, "Failed to set the timeout."); device->serial->ops->close (device->serial->port); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_close; } // Make sure everything is in a sane state. @@ -99,6 +108,10 @@ shearwater_common_custom_open (shearwater_common_device_t *device, dc_context_t device->serial->ops->flush (device->serial->port, SERIAL_QUEUE_BOTH); return DC_STATUS_SUCCESS; + +error_close: + serial_close (device->serial->port); + return status; } diff --git a/src/shearwater_petrel.c b/src/shearwater_petrel.c index e33dc8f..48548c8 100644 --- a/src/shearwater_petrel.c +++ b/src/shearwater_petrel.c @@ -52,6 +52,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 */ @@ -80,34 +81,35 @@ 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 *) 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)); // 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } @@ -148,7 +150,6 @@ shearwater_petrel_device_custom_open (dc_device_t **out, dc_context_t *context, 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. @@ -156,12 +157,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 4901787..5304284 100644 --- a/src/shearwater_predator.c +++ b/src/shearwater_predator.c @@ -53,6 +53,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 */ @@ -66,34 +67,35 @@ 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 *) 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)); // 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } @@ -134,16 +136,9 @@ shearwater_predator_device_custom_open (dc_device_t **out, dc_context_t *context 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 f1b8747..65c0e18 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -74,35 +74,62 @@ 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 = { + sizeof(shearwater_predator_parser_t), DC_FAMILY_SHEARWATER_PREDATOR, shearwater_predator_parser_set_data, /* set_data */ 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 = { + sizeof(shearwater_predator_parser_t), DC_FAMILY_SHEARWATER_PETREL, shearwater_predator_parser_set_data, /* set_data */ 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 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 serial, 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; @@ -149,16 +176,6 @@ shearwater_petrel_parser_create (dc_parser_t **out, dc_context_t *context, unsig } -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) { @@ -443,7 +460,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 @@ -481,11 +505,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_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 fa4a263..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 */ @@ -129,18 +130,21 @@ 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 *) 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; @@ -149,33 +153,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 +186,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,24 +204,27 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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_d9_parser.c b/src/suunto_d9_parser.c index 9931814..8d5c3c6 100644 --- a/src/suunto_d9_parser.c +++ b/src/suunto_d9_parser.c @@ -85,17 +85,30 @@ 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 = { + sizeof(suunto_d9_parser_t), DC_FAMILY_SUUNTO_D9, suunto_d9_parser_set_data, /* set_data */ 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 +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) @@ -192,19 +205,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, unsigned int serial) { + 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->serial = serial; @@ -224,16 +236,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) { @@ -505,12 +507,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 @@ -519,7 +525,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; @@ -686,10 +692,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 @@ -709,10 +724,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_eon.c b/src/suunto_eon.c index c9c78d2..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 */ @@ -71,18 +72,21 @@ 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 *) 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; @@ -91,56 +95,56 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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_eon_parser.c b/src/suunto_eon_parser.c index a803801..70fa74f 100644 --- a/src/suunto_eon_parser.c +++ b/src/suunto_eon_parser.c @@ -47,15 +47,15 @@ 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 = { + sizeof(suunto_eon_parser_t), DC_FAMILY_SUUNTO_EON, suunto_eon_parser_set_data, /* set_data */ 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 @@ -111,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; @@ -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 fcd46ca..be72ba5 100644 --- a/src/suunto_eonsteel.c +++ b/src/suunto_eonsteel.c @@ -40,7 +40,7 @@ #if __APPLE__ && HAVE_HIDAPI #include "hidapi/hidapi.h" #endif -#ifdef HAVE_LIBUSB +#if HAVE_LIBUSB || (__APPLE__ && HAVE_HIDAPI) #ifdef _WIN32 #define NOGDI @@ -92,6 +92,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 */ @@ -579,12 +580,13 @@ 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) { - suunto_eonsteel_device_t *eon; + dc_status_t status = DC_STATUS_SUCCESS; + 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; @@ -592,39 +594,35 @@ 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 __APPLE__ && HAVE_HIDAPI if (hid_init()) { ERROR(context, "hid_init() failed"); - free(eon); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_free; } eon->handle = hid_open(0x1493, 0x0030, NULL); if (!eon->handle) { ERROR(context, "unable to open device"); hid_exit(); - free(eon); - return DC_STATUS_IO; + status = DC_STATUS_IO; + goto error_usb_exit; } #else 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) @@ -635,20 +633,31 @@ suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, const char #endif if (initialize_eonsteel(eon) < 0) { ERROR(context, "unable to initialize device"); -#if __APPLE__ && HAVE_HIDAPI - hid_close(eon->handle); - hid_exit(); -#else - libusb_close(eon->handle); - libusb_exit(eon->ctx); -#endif - 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: +#if __APPLE__ && HAVE_HIDAPI + hid_close(eon->handle); +#else + libusb_close(eon->handle); +#endif + +error_usb_exit: +#if __APPLE__ && HAVE_HIDAPI + hid_exit(); +#else + libusb_exit(eon->ctx); +#endif + +error_free: + free(eon); + return status; } static int count_dir_entries(struct directory_entry *de) diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index f770dad..276eaa2 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -567,20 +567,23 @@ 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.value = o2 | (he << 16); + sample.event.time = 0; sample.event.flags = idx; + sample.event.value = o2 | (he << 16); if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata); +#endif } /* @@ -1300,11 +1303,12 @@ 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; } 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 */ @@ -1316,18 +1320,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 1d7b227..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 */ @@ -65,19 +66,19 @@ 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 *) 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; @@ -85,56 +86,56 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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_solution_parser.c b/src/suunto_solution_parser.c index 94e146a..8372457 100644 --- a/src/suunto_solution_parser.c +++ b/src/suunto_solution_parser.c @@ -42,34 +42,33 @@ 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 = { + sizeof(suunto_solution_parser_t), DC_FAMILY_SUUNTO_SOLUTION, suunto_solution_parser_set_data, /* set_data */ NULL, /* datetime */ suunto_solution_parser_get_field, /* fields */ suunto_solution_parser_samples_foreach, /* samples_foreach */ - suunto_solution_parser_destroy /* destroy */ + NULL /* destroy */ }; 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; @@ -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 b259259..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 */ @@ -91,18 +92,21 @@ 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 *) 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; @@ -111,33 +115,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,24 +150,27 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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 e6dbd27..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 */ @@ -80,18 +81,21 @@ 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 *) 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; @@ -100,33 +104,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 +140,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,24 +156,27 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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/suunto_vyper_parser.c b/src/suunto_vyper_parser.c index 946dcaf..7eee580 100644 --- a/src/suunto_vyper_parser.c +++ b/src/suunto_vyper_parser.c @@ -48,17 +48,29 @@ 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 = { + sizeof(suunto_vyper_parser_t), DC_FAMILY_SUUNTO_VYPER, suunto_vyper_parser_set_data, /* set_data */ 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 +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) @@ -149,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; @@ -178,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) { @@ -353,6 +354,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 +384,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_aladin.c b/src/uwatec_aladin.c index d01a92a..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 */ @@ -74,19 +75,19 @@ 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 *) 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; @@ -97,57 +98,57 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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 101ff19..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 */ @@ -70,19 +71,19 @@ 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 *) 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; @@ -93,34 +94,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,24 +127,27 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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_memomouse_parser.c b/src/uwatec_memomouse_parser.c index a47cdc4..ce52200 100644 --- a/src/uwatec_memomouse_parser.c +++ b/src/uwatec_memomouse_parser.c @@ -42,34 +42,33 @@ 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 = { + sizeof(uwatec_memomouse_parser_t), DC_FAMILY_UWATEC_MEMOMOUSE, uwatec_memomouse_parser_set_data, /* set_data */ 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 */ }; 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; @@ -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 fbf26c7..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 */ @@ -186,19 +187,19 @@ 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 *) 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; @@ -209,25 +210,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,24 +238,27 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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 124ffca..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 */ @@ -145,19 +146,19 @@ 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 *) 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; @@ -169,33 +170,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,24 +202,27 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index 969c7e4..eaa72d6 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -150,15 +150,15 @@ 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 = { + sizeof(uwatec_smart_parser_t), DC_FAMILY_UWATEC_SMART, uwatec_smart_parser_set_data, /* set_data */ 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 @@ -512,19 +512,19 @@ 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 *) 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; @@ -594,8 +594,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,16 +616,10 @@ uwatec_smart_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i *out = (dc_parser_t*) parser; return DC_STATUS_SUCCESS; -} - -static dc_status_t -uwatec_smart_parser_destroy (dc_parser_t *abstract) -{ - // Free memory. - free (abstract); - - return DC_STATUS_SUCCESS; +error_free: + dc_parser_deallocate ((dc_parser_t *) parser); + return status; } @@ -1115,6 +1109,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 +1119,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; } diff --git a/src/zeagle_n2ition3.c b/src/zeagle_n2ition3.c index 1c1dcf1..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 */ @@ -137,19 +138,19 @@ 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 *) 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)); @@ -158,25 +159,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,24 +187,27 @@ 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: + dc_device_deallocate ((dc_device_t *) device); + return status; } 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; }