From b5503e53fd7555cfbc5da6a582d8e60b5e10eef8 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Mon, 28 Dec 2015 07:26:07 +0100 Subject: [PATCH] Add a more modular example application. The universal application works well, but is quite difficult to extend with more functionality. Therefore a new and more modular application is needed. The new dctool application will support multiple sub-commands, to carry out specific actions. Extending the application will be as easy as adding new commands. --- configure.ac | 2 + examples/Makefile.am | 14 +- examples/common.c | 66 --- examples/dctool.c | 125 ++++ examples/{common.h => dctool.h} | 23 +- examples/hw_ostc_fwupdate.c | 145 ----- examples/universal.c | 979 -------------------------------- 7 files changed, 144 insertions(+), 1210 deletions(-) delete mode 100644 examples/common.c create mode 100644 examples/dctool.c rename examples/{common.h => dctool.h} (69%) delete mode 100644 examples/hw_ostc_fwupdate.c delete mode 100644 examples/universal.c diff --git a/configure.ac b/configure.ac index 047b3f0..ca071fa 100644 --- a/configure.ac +++ b/configure.ac @@ -105,10 +105,12 @@ AM_CONDITIONAL([IRDA], [test "$irda_win32" = "yes" || test "$irda_linux" = "yes" # Checks for header files. AC_CHECK_HEADERS([linux/serial.h]) AC_CHECK_HEADERS([IOKit/serial/ioss.h]) +AC_CHECK_HEADERS([getopt.h]) # Checks for library functions. AC_FUNC_STRERROR_R AC_CHECK_FUNCS([localtime_r gmtime_r]) +AC_CHECK_FUNCS([getopt_long]) # Versioning. AC_SUBST([DC_VERSION],[dc_version]) diff --git a/examples/Makefile.am b/examples/Makefile.am index d77db45..ddbade4 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -2,12 +2,10 @@ AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include LDADD = $(top_builddir)/src/libdivecomputer.la bin_PROGRAMS = \ - universal \ - ostc-fwupdate + dctool -COMMON = common.c common.h \ - utils.c utils.h - -universal_SOURCES = universal.c $(COMMON) - -ostc_fwupdate_SOURCES = hw_ostc_fwupdate.c $(COMMON) +dctool_SOURCES = \ + dctool.h \ + dctool.c \ + utils.h \ + utils.c diff --git a/examples/common.c b/examples/common.c deleted file mode 100644 index f69e7e4..0000000 --- a/examples/common.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * libdivecomputer - * - * Copyright (C) 2011 Jef Driesen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ - -#include "common.h" -#include "utils.h" - -const char * -errmsg (dc_status_t rc) -{ - switch (rc) { - case DC_STATUS_SUCCESS: - return "Success"; - case DC_STATUS_UNSUPPORTED: - return "Unsupported operation"; - case DC_STATUS_INVALIDARGS: - return "Invalid arguments"; - case DC_STATUS_NOMEMORY: - return "Out of memory"; - case DC_STATUS_NODEVICE: - return "No device found"; - case DC_STATUS_NOACCESS: - return "Access denied"; - case DC_STATUS_IO: - return "Input/output error"; - case DC_STATUS_TIMEOUT: - return "Timeout"; - case DC_STATUS_PROTOCOL: - return "Protocol error"; - case DC_STATUS_DATAFORMAT: - return "Data format error"; - case DC_STATUS_CANCELLED: - return "Cancelled"; - default: - return "Unknown error"; - } -} - -void -logfunc (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *msg, void *userdata) -{ - const char *loglevels[] = {"NONE", "ERROR", "WARNING", "INFO", "DEBUG", "ALL"}; - - if (loglevel == DC_LOGLEVEL_ERROR || loglevel == DC_LOGLEVEL_WARNING) { - message ("%s: %s [in %s:%d (%s)]\n", loglevels[loglevel], msg, file, line, function); - } else { - message ("%s: %s\n", loglevels[loglevel], msg); - } -} diff --git a/examples/dctool.c b/examples/dctool.c new file mode 100644 index 0000000..b0b0c9c --- /dev/null +++ b/examples/dctool.c @@ -0,0 +1,125 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif + +#include "dctool.h" +#include "utils.h" + +#if defined(__GLIBC__) || defined(__MINGW32__) +#define NOPERMUTATION "+" +#define RESET 0 +#else +#define NOPERMUTATION "" +#define RESET 1 +#endif + +static const dctool_command_t *g_commands[] = { + NULL +}; + +const dctool_command_t * +dctool_command_find (const char *name) +{ + if (name == NULL) + return NULL; + + size_t i = 0; + while (g_commands[i] != NULL) { + if (strcmp(g_commands[i]->name, name) == 0) { + break; + } + i++; + } + + return g_commands[i]; +} + +int +main (int argc, char *argv[]) +{ + // Default option values. + unsigned int help = 0; + + // Parse the command-line options. + int opt = 0; + const char *optstring = NOPERMUTATION "h"; +#ifdef HAVE_GETOPT_LONG + struct option options[] = { + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0 } + }; + while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { +#else + while ((opt = getopt (argc, argv, optstring)) != -1) { +#endif + switch (opt) { + case 'h': + help = 1; + break; + default: + return EXIT_FAILURE; + } + } + + // Skip the processed arguments. + argc -= optind; + argv += optind; + optind = RESET; + + // Show help message. + if (help || argv[0] == NULL) { + printf ( + "A simple command line interface for the libdivecomputer library\n" + "\n" + "Usage:\n" + " dctool [options] []\n" + "\n" + "Options:\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help Show help message\n" +#else + " -h Show help message\n" +#endif + "\n"); + return EXIT_SUCCESS; + } + + // Try to find the command. + const dctool_command_t *command = dctool_command_find (argv[0]); + if (command == NULL) { + message ("Unknown command %s.\n", argv[0]); + return EXIT_FAILURE; + } + + // Execute the command. + return command->run (argc, argv); +} diff --git a/examples/common.h b/examples/dctool.h similarity index 69% rename from examples/common.h rename to examples/dctool.h index 4c23f1b..6443caf 100644 --- a/examples/common.h +++ b/examples/dctool.h @@ -1,7 +1,7 @@ /* * libdivecomputer * - * Copyright (C) 2011 Jef Driesen + * Copyright (C) 2015 Jef Driesen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,23 +19,22 @@ * MA 02110-1301 USA */ -#ifndef EXAMPLES_COMMON_H -#define EXAMPLES_COMMON_H - -#include -#include +#ifndef DCTOOL_H +#define DCTOOL_H #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -const char * -errmsg (dc_status_t rc); - -void -logfunc (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *msg, void *userdata); +typedef struct dctool_command_t { + int (*run) (int argc, char *argv[]); + const char *name; + const char *description; + const char *usage; +} dctool_command_t; #ifdef __cplusplus } #endif /* __cplusplus */ -#endif /* EXAMPLES_COMMON_H */ + +#endif /* DCTOOL_H */ diff --git a/examples/hw_ostc_fwupdate.c b/examples/hw_ostc_fwupdate.c deleted file mode 100644 index 8fa5c31..0000000 --- a/examples/hw_ostc_fwupdate.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * libdivecomputer - * - * Copyright (C) 2013 Jef Driesen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ - -#include - -#include -#include - -#include "utils.h" -#include "common.h" - -static void -event_cb (dc_device_t *device, dc_event_type_t event, const void *data, void *userdata) -{ - const dc_event_progress_t *progress = (dc_event_progress_t *) data; - - switch (event) { - case DC_EVENT_PROGRESS: - message ("Event: progress %3.2f%% (%u/%u)\n", - 100.0 * (double) progress->current / (double) progress->maximum, - progress->current, progress->maximum); - break; - default: - break; - } -} - -static dc_status_t -fwupdate (const char *name, const char *hexfile, int ostc3) -{ - dc_context_t *context = NULL; - dc_device_t *device = NULL; - dc_status_t rc = DC_STATUS_SUCCESS; - - dc_context_new (&context); - dc_context_set_loglevel (context, DC_LOGLEVEL_ALL); - dc_context_set_logfunc (context, logfunc, NULL); - - if (ostc3) { - message ("hw_ostc3_device_open\n"); - rc = hw_ostc3_device_open (&device, context, name); - } else { - message ("hw_ostc_device_open\n"); - rc = hw_ostc_device_open (&device, context, name); - } - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error opening serial port."); - dc_context_free (context); - return rc; - } - - message ("dc_device_set_events.\n"); - rc = dc_device_set_events (device, DC_EVENT_PROGRESS, event_cb, NULL); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error registering the event handler."); - dc_device_close (device); - dc_context_free (context); - return rc; - } - - if (ostc3) { - message ("hw_ostc3_device_fwupdate\n"); - rc = hw_ostc3_device_fwupdate (device, hexfile); - } else { - message ("hw_ostc_device_fwupdate\n"); - rc = hw_ostc_device_fwupdate (device, hexfile); - } - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error flashing firmware."); - dc_device_close (device); - dc_context_free (context); - return rc; - } - - message ("dc_device_close\n"); - rc = dc_device_close (device); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Cannot close device."); - dc_context_free (context); - return rc; - } - - dc_context_free (context); - - return DC_STATUS_SUCCESS; -} - - -int main(int argc, char *argv[]) -{ - message_set_logfile ("OSTC-FWUPDATE.LOG"); - -#ifdef _WIN32 - const char* name = "COM1"; -#else - const char* name = "/dev/ttyUSB0"; -#endif - const char *hexfile = NULL; - int ostc3 = 0; - - if (argc > 1) { - name = argv[1]; - } - if (argc > 2) { - hexfile = argv[2]; - } - if (argc > 3) { - if (strcmp(argv[3], "-3") == 0) { - ostc3 = 1; - } else { - ostc3 = 0; - } - } - - message ("DEVICE=%s\n", name); - message ("HEXFILE=%s\n", hexfile); - - dc_status_t a = fwupdate (name, hexfile, ostc3); - - message ("SUMMARY\n"); - message ("-------\n"); - message ("fwupdate: %s\n", errmsg (a)); - - message_set_logfile (NULL); - - return 0; -} diff --git a/examples/universal.c b/examples/universal.c deleted file mode 100644 index b4d9b47..0000000 --- a/examples/universal.c +++ /dev/null @@ -1,979 +0,0 @@ -/* - * libdivecomputer - * - * Copyright (C) 2009 Jef Driesen - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ - -#include // fopen, fwrite, fclose -#include -#include -#include - -#ifndef _MSC_VER -#include -#endif - -#ifdef _MSC_VER -#define snprintf _snprintf -#define strcasecmp _stricmp -#define strncasecmp _strnicmp -#endif - -#ifdef _WIN32 -#define DC_TICKS_FORMAT "%I64d" -#else -#define DC_TICKS_FORMAT "%lld" -#endif - -#include -#include -#include - -#include "utils.h" -#include "common.h" - -static const char *g_cachedir = NULL; -static int g_cachedir_read = 1; - -typedef struct device_data_t { - dc_event_devinfo_t devinfo; - dc_event_clock_t clock; -} device_data_t; - -typedef struct dive_data_t { - dc_device_t *device; - FILE* fp; - unsigned int number; - dc_buffer_t *fingerprint; -} dive_data_t; - -typedef struct sample_data_t { - FILE* fp; - unsigned int nsamples; -} sample_data_t; - -typedef struct backend_table_t { - const char *name; - dc_family_t type; -} backend_table_t; - -static const backend_table_t g_backends[] = { - {"solution", DC_FAMILY_SUUNTO_SOLUTION}, - {"eon", DC_FAMILY_SUUNTO_EON}, - {"vyper", DC_FAMILY_SUUNTO_VYPER}, - {"vyper2", DC_FAMILY_SUUNTO_VYPER2}, - {"d9", DC_FAMILY_SUUNTO_D9}, - {"eonsteel", DC_FAMILY_SUUNTO_EONSTEEL}, - {"aladin", DC_FAMILY_UWATEC_ALADIN}, - {"memomouse", DC_FAMILY_UWATEC_MEMOMOUSE}, - {"smart", DC_FAMILY_UWATEC_SMART}, - {"meridian", DC_FAMILY_UWATEC_MERIDIAN}, - {"sensus", DC_FAMILY_REEFNET_SENSUS}, - {"sensuspro", DC_FAMILY_REEFNET_SENSUSPRO}, - {"sensusultra", DC_FAMILY_REEFNET_SENSUSULTRA}, - {"vtpro", DC_FAMILY_OCEANIC_VTPRO}, - {"veo250", DC_FAMILY_OCEANIC_VEO250}, - {"atom2", DC_FAMILY_OCEANIC_ATOM2}, - {"nemo", DC_FAMILY_MARES_NEMO}, - {"puck", DC_FAMILY_MARES_PUCK}, - {"darwin", DC_FAMILY_MARES_DARWIN}, - {"iconhd", DC_FAMILY_MARES_ICONHD}, - {"ostc", DC_FAMILY_HW_OSTC}, - {"frog", DC_FAMILY_HW_FROG}, - {"ostc3", DC_FAMILY_HW_OSTC3}, - {"edy", DC_FAMILY_CRESSI_EDY}, - {"leonardo", DC_FAMILY_CRESSI_LEONARDO}, - {"n2ition3", DC_FAMILY_ZEAGLE_N2ITION3}, - {"cobalt", DC_FAMILY_ATOMICS_COBALT}, - {"predator", DC_FAMILY_SHEARWATER_PREDATOR}, - {"petrel", DC_FAMILY_SHEARWATER_PETREL}, - {"nitekq", DC_FAMILY_DIVERITE_NITEKQ}, - {"aqualand", DC_FAMILY_CITIZEN_AQUALAND}, - {"idive", DC_FAMILY_DIVESYSTEM_IDIVE}, -}; - -static dc_family_t -lookup_type (const char *name) -{ - unsigned int nbackends = sizeof (g_backends) / sizeof (g_backends[0]); - for (unsigned int i = 0; i < nbackends; ++i) { - if (strcmp (name, g_backends[i].name) == 0) - return g_backends[i].type; - } - - return DC_FAMILY_NULL; -} - -static const char * -lookup_name (dc_family_t type) -{ - unsigned int nbackends = sizeof (g_backends) / sizeof (g_backends[0]); - for (unsigned int i = 0; i < nbackends; ++i) { - if (g_backends[i].type == type) - return g_backends[i].name; - } - - return NULL; -} - -static unsigned char -hex2dec (unsigned char value) -{ - if (value >= '0' && value <= '9') - return value - '0'; - else if (value >= 'A' && value <= 'F') - return value - 'A' + 10; - else if (value >= 'a' && value <= 'f') - return value - 'a' + 10; - else - return 0; -} - -static dc_buffer_t * -fpconvert (const char *fingerprint) -{ - // Get the length of the fingerprint data. - size_t nbytes = (fingerprint ? strlen (fingerprint) / 2 : 0); - if (nbytes == 0) - return NULL; - - // Allocate a memory buffer. - dc_buffer_t *buffer = dc_buffer_new (nbytes); - - // Convert the hexadecimal string. - for (unsigned int i = 0; i < nbytes; ++i) { - unsigned char msn = hex2dec (fingerprint[i * 2 + 0]); - unsigned char lsn = hex2dec (fingerprint[i * 2 + 1]); - unsigned char byte = (msn << 4) + lsn; - - dc_buffer_append (buffer, &byte, 1); - } - - return buffer; -} - -static dc_buffer_t * -fpread (const char *dirname, dc_family_t backend, unsigned int serial) -{ - // Build the filename. - char filename[1024] = {0}; - snprintf (filename, sizeof (filename), "%s/%s-%08X.bin", - dirname, lookup_name (backend), serial); - - // Open the fingerprint file. - FILE *fp = fopen (filename, "rb"); - if (fp == NULL) - return NULL; - - // Allocate a memory buffer. - dc_buffer_t *buffer = dc_buffer_new (0); - - // Read the entire file into the buffer. - size_t n = 0; - unsigned char block[1024] = {0}; - while ((n = fread (block, 1, sizeof (block), fp)) > 0) { - dc_buffer_append (buffer, block, n); - } - - // Close the file. - fclose (fp); - - return buffer; -} - -static void -fpwrite (dc_buffer_t *buffer, const char *dirname, dc_family_t backend, unsigned int serial) -{ - // Check the buffer size. - if (dc_buffer_get_size (buffer) == 0) - return; - - // Build the filename. - char filename[1024] = {0}; - snprintf (filename, sizeof (filename), "%s/%s-%08X.bin", - dirname, lookup_name (backend), serial); - - // Open the fingerprint file. - FILE *fp = fopen (filename, "wb"); - if (fp == NULL) - return; - - // Write the fingerprint data. - fwrite (dc_buffer_get_data (buffer), 1, dc_buffer_get_size (buffer), fp); - - // Close the file. - fclose (fp); -} - -volatile sig_atomic_t g_cancel = 0; - -void -sighandler (int signum) -{ -#ifndef _WIN32 - // Restore the default signal handler. - signal (signum, SIG_DFL); -#endif - - g_cancel = 1; -} - -static int -cancel_cb (void *userdata) -{ - return g_cancel; -} - -void -sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata) -{ - static const char *events[] = { - "none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter", - "violation", "bookmark", "surface", "safety stop", "gaschange", - "safety stop (voluntary)", "safety stop (mandatory)", "deepstop", - "ceiling (safety stop)", "floor", "divetime", "maxdepth", - "OLF", "PO2", "airtime", "rgbm", "heading", "tissue level warning", - "gaschange2"}; - static const char *decostop[] = { - "ndl", "safety", "deco", "deep"}; - - sample_data_t *sampledata = (sample_data_t *) userdata; - - switch (type) { - case DC_SAMPLE_TIME: - if (sampledata->nsamples++) - fprintf (sampledata->fp, "\n"); - fprintf (sampledata->fp, "\n"); - fprintf (sampledata->fp, " \n", value.time / 60, value.time % 60); - break; - case DC_SAMPLE_DEPTH: - fprintf (sampledata->fp, " %.2f\n", value.depth); - break; - case DC_SAMPLE_PRESSURE: - fprintf (sampledata->fp, " %.2f\n", value.pressure.tank, value.pressure.value); - break; - case DC_SAMPLE_TEMPERATURE: - fprintf (sampledata->fp, " %.2f\n", value.temperature); - break; - case DC_SAMPLE_EVENT: - if (value.event.type == SAMPLE_EVENT_GASCHANGE || value.event.type == SAMPLE_EVENT_GASCHANGE2) { - // Ignore deprecated events. - } else { - fprintf (sampledata->fp, " %s\n", - value.event.type, value.event.time, value.event.flags, value.event.value, events[value.event.type]); - } - break; - case DC_SAMPLE_RBT: - fprintf (sampledata->fp, " %u\n", value.rbt); - break; - case DC_SAMPLE_HEARTBEAT: - fprintf (sampledata->fp, " %u\n", value.heartbeat); - break; - case DC_SAMPLE_BEARING: - fprintf (sampledata->fp, " %u\n", value.bearing); - break; - case DC_SAMPLE_VENDOR: - fprintf (sampledata->fp, " ", value.vendor.type, value.vendor.size); - for (unsigned int i = 0; i < value.vendor.size; ++i) - fprintf (sampledata->fp, "%02X", ((unsigned char *) value.vendor.data)[i]); - fprintf (sampledata->fp, "\n"); - break; - case DC_SAMPLE_SETPOINT: - fprintf (sampledata->fp, " %.2f\n", value.setpoint); - break; - case DC_SAMPLE_PPO2: - fprintf (sampledata->fp, " %.2f\n", value.ppo2); - break; - case DC_SAMPLE_CNS: - fprintf (sampledata->fp, " %.1f\n", value.cns * 100.0); - break; - case DC_SAMPLE_DECO: - fprintf (sampledata->fp, " %s\n", - value.deco.time, value.deco.depth, decostop[value.deco.type]); - break; - case DC_SAMPLE_GASMIX: - fprintf (sampledata->fp, " %u\n", value.gasmix); - break; - default: - break; - } -} - - -static dc_status_t -doparse (FILE *fp, dc_device_t *device, const unsigned char data[], unsigned int size) -{ - // Create the parser. - message ("Creating the parser.\n"); - dc_parser_t *parser = NULL; - dc_status_t rc = dc_parser_new (&parser, device); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error creating the parser."); - return rc; - } - - // Register the data. - message ("Registering the data.\n"); - rc = dc_parser_set_data (parser, data, size); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error registering the data."); - dc_parser_destroy (parser); - return rc; - } - - // Parse the datetime. - message ("Parsing the datetime.\n"); - dc_datetime_t dt = {0}; - rc = dc_parser_get_datetime (parser, &dt); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the datetime."); - dc_parser_destroy (parser); - return rc; - } - - fprintf (fp, "%04i-%02i-%02i %02i:%02i:%02i\n", - dt.year, dt.month, dt.day, - dt.hour, dt.minute, dt.second); - - // Parse the divetime. - message ("Parsing the divetime.\n"); - unsigned int divetime = 0; - rc = dc_parser_get_field (parser, DC_FIELD_DIVETIME, 0, &divetime); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the divetime."); - dc_parser_destroy (parser); - return rc; - } - - fprintf (fp, "%02u:%02u\n", - divetime / 60, divetime % 60); - - // Parse the temperature. - message ("Parsing the temperature.\n"); - for (unsigned int i = 0; i < 3; ++i) { - dc_field_type_t fields[] = {DC_FIELD_TEMPERATURE_SURFACE, - DC_FIELD_TEMPERATURE_MINIMUM, - DC_FIELD_TEMPERATURE_MAXIMUM}; - const char *names[] = {"surface", "minimum", "maximum"}; - - double temperature = 0.0; - rc = dc_parser_get_field (parser, fields[i], 0, &temperature); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the temperature."); - dc_parser_destroy (parser); - return rc; - } - - if (rc != DC_STATUS_UNSUPPORTED) { - fprintf (fp, "%.1f\n", - names[i], temperature); - } - } - - // Parse the maxdepth. - message ("Parsing the maxdepth.\n"); - double maxdepth = 0.0; - rc = dc_parser_get_field (parser, DC_FIELD_MAXDEPTH, 0, &maxdepth); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the maxdepth."); - dc_parser_destroy (parser); - return rc; - } - - fprintf (fp, "%.2f\n", - maxdepth); - - // Parse the gas mixes. - message ("Parsing the gas mixes.\n"); - unsigned int ngases = 0; - rc = dc_parser_get_field (parser, DC_FIELD_GASMIX_COUNT, 0, &ngases); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the gas mix count."); - dc_parser_destroy (parser); - return rc; - } - - for (unsigned int i = 0; i < ngases; ++i) { - dc_gasmix_t gasmix = {0}; - rc = dc_parser_get_field (parser, DC_FIELD_GASMIX, i, &gasmix); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the gas mix."); - dc_parser_destroy (parser); - return rc; - } - - fprintf (fp, - "\n" - " %.1f\n" - " %.1f\n" - " %.1f\n" - "\n", - gasmix.helium * 100.0, - gasmix.oxygen * 100.0, - gasmix.nitrogen * 100.0); - } - - // Parse the tanks. - message ("Parsing the tanks.\n"); - unsigned int ntanks = 0; - rc = dc_parser_get_field (parser, DC_FIELD_TANK_COUNT, 0, &ntanks); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the tank count."); - dc_parser_destroy (parser); - return rc; - } - - for (unsigned int i = 0; i < ntanks; ++i) { - const char *names[] = {"none", "metric", "imperial"}; - - dc_tank_t tank = {0}; - rc = dc_parser_get_field (parser, DC_FIELD_TANK, i, &tank); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the tank."); - dc_parser_destroy (parser); - return rc; - } - - fprintf (fp, "\n"); - if (tank.gasmix != DC_GASMIX_UNKNOWN) { - fprintf (fp, - " %u\n", - tank.gasmix); - } - if (tank.type != DC_TANKVOLUME_NONE) { - fprintf (fp, - " %s\n" - " %.1f\n" - " %.2f\n", - names[tank.type], tank.volume, tank.workpressure); - } - fprintf (fp, - " %.2f\n" - " %.2f\n" - "\n", - tank.beginpressure, tank.endpressure); - } - - // Parse the dive mode. - message ("Parsing the dive mode.\n"); - dc_divemode_t divemode = DC_DIVEMODE_OC; - rc = dc_parser_get_field (parser, DC_FIELD_DIVEMODE, 0, &divemode); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the dive mode."); - dc_parser_destroy (parser); - return rc; - } - - if (rc != DC_STATUS_UNSUPPORTED) { - const char *names[] = {"freedive", "gauge", "oc", "cc"}; - fprintf (fp, "%s\n", - names[divemode]); - } - - // Parse the salinity. - message ("Parsing the salinity.\n"); - dc_salinity_t salinity = {DC_WATER_FRESH, 0.0}; - rc = dc_parser_get_field (parser, DC_FIELD_SALINITY, 0, &salinity); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the salinity."); - dc_parser_destroy (parser); - return rc; - } - - if (rc != DC_STATUS_UNSUPPORTED) { - fprintf (fp, "%.1f\n", - salinity.type, salinity.density); - } - - // Parse the atmospheric pressure. - message ("Parsing the atmospheric pressure.\n"); - double atmospheric = 0.0; - rc = dc_parser_get_field (parser, DC_FIELD_ATMOSPHERIC, 0, &atmospheric); - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { - WARNING ("Error parsing the atmospheric pressure."); - dc_parser_destroy (parser); - return rc; - } - - if (rc != DC_STATUS_UNSUPPORTED) { - fprintf (fp, "%.5f\n", - atmospheric); - } - - // Initialize the sample data. - sample_data_t sampledata = {0}; - sampledata.nsamples = 0; - sampledata.fp = fp; - - // Parse the sample data. - message ("Parsing the sample data.\n"); - rc = dc_parser_samples_foreach (parser, sample_cb, &sampledata); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error parsing the sample data."); - dc_parser_destroy (parser); - return rc; - } - - if (sampledata.nsamples) - fprintf (fp, "\n"); - - // Destroy the parser. - message ("Destroying the parser.\n"); - rc = dc_parser_destroy (parser); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error destroying the parser."); - return rc; - } - - return DC_STATUS_SUCCESS; -} - -static void -event_cb (dc_device_t *device, dc_event_type_t event, const void *data, void *userdata) -{ - const dc_event_progress_t *progress = (dc_event_progress_t *) data; - const dc_event_devinfo_t *devinfo = (dc_event_devinfo_t *) data; - const dc_event_clock_t *clock = (dc_event_clock_t *) data; - const dc_event_vendor_t *vendor = (dc_event_vendor_t *) data; - - device_data_t *devdata = (device_data_t *) userdata; - - switch (event) { - case DC_EVENT_WAITING: - message ("Event: waiting for user action\n"); - break; - case DC_EVENT_PROGRESS: - message ("Event: progress %3.2f%% (%u/%u)\n", - 100.0 * (double) progress->current / (double) progress->maximum, - progress->current, progress->maximum); - break; - case DC_EVENT_DEVINFO: - devdata->devinfo = *devinfo; - message ("Event: model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)\n", - devinfo->model, devinfo->model, - devinfo->firmware, devinfo->firmware, - devinfo->serial, devinfo->serial); - if (g_cachedir && g_cachedir_read) { - dc_buffer_t *fingerprint = fpread (g_cachedir, dc_device_get_type (device), devinfo->serial); - dc_device_set_fingerprint (device, - dc_buffer_get_data (fingerprint), - dc_buffer_get_size (fingerprint)); - dc_buffer_free (fingerprint); - } - break; - case DC_EVENT_CLOCK: - devdata->clock = *clock; - message ("Event: systime=" DC_TICKS_FORMAT ", devtime=%u\n", - clock->systime, clock->devtime); - break; - case DC_EVENT_VENDOR: - message ("Event: vendor="); - for (unsigned int i = 0; i < vendor->size; ++i) - message ("%02X", vendor->data[i]); - message ("\n"); - break; - default: - break; - } -} - -static int -dive_cb (const unsigned char *data, unsigned int size, const unsigned char *fingerprint, unsigned int fsize, void *userdata) -{ - dive_data_t *divedata = (dive_data_t *) userdata; - - divedata->number++; - - message ("Dive: number=%u, size=%u, fingerprint=", divedata->number, size); - for (unsigned int i = 0; i < fsize; ++i) - message ("%02X", fingerprint[i]); - message ("\n"); - - if (divedata->number == 1) { - divedata->fingerprint = dc_buffer_new (fsize); - dc_buffer_append (divedata->fingerprint, fingerprint, fsize); - } - - if (divedata->fp) { - fprintf (divedata->fp, "\n%u\n%u\n", divedata->number, size); - for (unsigned int i = 0; i < fsize; ++i) - fprintf (divedata->fp, "%02X", fingerprint[i]); - fprintf (divedata->fp, "\n"); - - doparse (divedata->fp, divedata->device, data, size); - - fprintf (divedata->fp, "\n"); - } - - return 1; -} - - -static void -usage (const char *filename) -{ -#ifndef _MSC_VER - fprintf (stderr, "Usage:\n\n"); - fprintf (stderr, " %s [options] devname\n\n", filename); - fprintf (stderr, "Options:\n\n"); - fprintf (stderr, " -n name Set device name (required).\n"); - fprintf (stderr, " -b name Set backend name (required).\n"); - fprintf (stderr, " -t model Set model code.\n"); - fprintf (stderr, " -f hexdata Set fingerprint data.\n"); - fprintf (stderr, " -l logfile Set logfile.\n"); - fprintf (stderr, " -d filename Download dives.\n"); - fprintf (stderr, " -m filename Download memory dump.\n"); - fprintf (stderr, " -c cachedir Set cache directory.\n"); - fprintf (stderr, " -h Show this help message.\n\n"); -#else - fprintf (stderr, "Usage:\n\n"); - fprintf (stderr, " %s backend devname\n\n", filename); -#endif - - fprintf (stderr, "Supported backends:\n\n"); - unsigned int nbackends = sizeof (g_backends) / sizeof (g_backends[0]); - for (unsigned int i = 0; i < nbackends; ++i) { - fprintf (stderr, "%s", g_backends[i].name); - if (i != nbackends - 1) - fprintf (stderr, ", "); - else - fprintf (stderr, "\n\n"); - } - - fprintf (stderr, "Supported devices:\n\n"); - dc_iterator_t *iterator = NULL; - dc_descriptor_t *descriptor = NULL; - dc_descriptor_iterator (&iterator); - while (dc_iterator_next (iterator, &descriptor) == DC_STATUS_SUCCESS) { - fprintf (stderr, " %s %s\n", - dc_descriptor_get_vendor (descriptor), - dc_descriptor_get_product (descriptor)); - dc_descriptor_free (descriptor); - } - dc_iterator_free (iterator); -} - - -static dc_status_t -search (dc_descriptor_t **out, const char *name, dc_family_t backend, unsigned int model) -{ - dc_status_t rc = DC_STATUS_SUCCESS; - - dc_iterator_t *iterator = NULL; - rc = dc_descriptor_iterator (&iterator); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error creating the device descriptor iterator."); - return rc; - } - - dc_descriptor_t *descriptor = NULL, *current = NULL; - while ((rc = dc_iterator_next (iterator, &descriptor)) == DC_STATUS_SUCCESS) { - if (name) { - const char *vendor = dc_descriptor_get_vendor (descriptor); - const char *product = dc_descriptor_get_product (descriptor); - - size_t n = strlen (vendor); - if (strncasecmp (name, vendor, n) == 0 && name[n] == ' ' && - strcasecmp (name + n + 1, product) == 0) - { - current = descriptor; - break; - } else if (strcasecmp (name, product) == 0) { - current = descriptor; - break; - } - } else { - if (backend == dc_descriptor_get_type (descriptor)) { - if (model == dc_descriptor_get_model (descriptor)) { - // Exact match found. Return immediately. - dc_descriptor_free (current); - current = descriptor; - break; - } else { - // Possible match found. Keep searching for an exact match. - // If no exact match is found, the first match is returned. - if (current == NULL) { - current = descriptor; - descriptor = NULL; - } - } - } - } - - dc_descriptor_free (descriptor); - } - - if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_DONE) { - dc_descriptor_free (current); - dc_iterator_free (iterator); - WARNING ("Error iterating the device descriptors."); - return rc; - } - - dc_iterator_free (iterator); - - *out = current; - - return DC_STATUS_SUCCESS; -} - - -static dc_status_t -dowork (dc_context_t *context, dc_descriptor_t *descriptor, const char *devname, const char *rawfile, const char *xmlfile, int memory, int dives, dc_buffer_t *fingerprint) -{ - dc_status_t rc = DC_STATUS_SUCCESS; - - // Initialize the device data. - device_data_t devdata = {{0}}; - - // Open the device. - message ("Opening the device (%s %s, %s).\n", - dc_descriptor_get_vendor (descriptor), - dc_descriptor_get_product (descriptor), - devname ? devname : "null"); - dc_device_t *device = NULL; - rc = dc_device_open (&device, context, descriptor, devname); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error opening device."); - return rc; - } - - // Register the event handler. - message ("Registering the event handler.\n"); - int events = DC_EVENT_WAITING | DC_EVENT_PROGRESS | DC_EVENT_DEVINFO | DC_EVENT_CLOCK | DC_EVENT_VENDOR; - rc = dc_device_set_events (device, events, event_cb, &devdata); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error registering the event handler."); - dc_device_close (device); - return rc; - } - - // Register the cancellation handler. - message ("Registering the cancellation handler.\n"); - rc = dc_device_set_cancel (device, cancel_cb, NULL); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error registering the cancellation handler."); - dc_device_close (device); - return rc; - } - - // Register the fingerprint data. - if (fingerprint) { - message ("Registering the fingerprint data.\n"); - rc = dc_device_set_fingerprint (device, dc_buffer_get_data (fingerprint), dc_buffer_get_size (fingerprint)); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error registering the fingerprint data."); - dc_device_close (device); - return rc; - } - } - - if (memory) { - // Allocate a memory buffer. - dc_buffer_t *buffer = dc_buffer_new (0); - - // Download the memory dump. - message ("Downloading the memory dump.\n"); - rc = dc_device_dump (device, buffer); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error downloading the memory dump."); - dc_buffer_free (buffer); - dc_device_close (device); - return rc; - } - - // Write the memory dump to disk. - FILE* fp = fopen (rawfile, "wb"); - if (fp != NULL) { - fwrite (dc_buffer_get_data (buffer), 1, dc_buffer_get_size (buffer), fp); - fclose (fp); - } - - // Free the memory buffer. - dc_buffer_free (buffer); - } - - if (dives) { - // Initialize the dive data. - dive_data_t divedata = {0}; - divedata.device = device; - divedata.fingerprint = NULL; - divedata.number = 0; - - // Open the output file. - divedata.fp = fopen (xmlfile, "w"); - - if (divedata.fp) { - fprintf (divedata.fp, "\n"); - } - - // Download the dives. - message ("Downloading the dives.\n"); - rc = dc_device_foreach (device, dive_cb, &divedata); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error downloading the dives."); - dc_buffer_free (divedata.fingerprint); - if (divedata.fp) fclose (divedata.fp); - dc_device_close (device); - return rc; - } - - if (divedata.fp) { - fprintf (divedata.fp, "\n"); - } - - // Store the fingerprint data. - if (g_cachedir) { - fpwrite (divedata.fingerprint, g_cachedir, dc_device_get_type (device), devdata.devinfo.serial); - } - - // Free the fingerprint buffer. - dc_buffer_free (divedata.fingerprint); - - // Close the output file. - if (divedata.fp) fclose (divedata.fp); - } - - // Close the device. - message ("Closing the device.\n"); - rc = dc_device_close (device); - if (rc != DC_STATUS_SUCCESS) { - WARNING ("Error closing the device."); - return rc; - } - - return DC_STATUS_SUCCESS; -} - - -int -main (int argc, char *argv[]) -{ - // Default values. - dc_family_t backend = DC_FAMILY_NULL; - dc_loglevel_t loglevel = DC_LOGLEVEL_WARNING; - const char *name = NULL; - const char *logfile = "output.log"; - const char *rawfile = "output.bin"; - const char *xmlfile = "output.xml"; - const char *devname = NULL; - const char *fingerprint = NULL; - unsigned int model = 0; - int memory = 0, dives = 0; - -#ifndef _MSC_VER - // Parse command-line options. - int opt = 0; - while ((opt = getopt (argc, argv, "n:b:t:f:l:m:d:c:vh")) != -1) { - switch (opt) { - case 'n': - name = optarg; - break; - case 'b': - backend = lookup_type (optarg); - break; - case 't': - model = strtoul (optarg, NULL, 0); - break; - case 'f': - fingerprint = optarg; - g_cachedir_read = 0; - break; - case 'l': - logfile = optarg; - break; - case 'v': - loglevel++; - break; - case 'm': - memory = 1; - rawfile = optarg; - break; - case 'd': - dives = 1; - xmlfile = optarg; - break; - case 'c': - g_cachedir = optarg; - break; - case '?': - case 'h': - default: - usage (argv[0]); - return EXIT_FAILURE; - } - } - - if (optind < argc) - devname = argv[optind]; -#else - if (argc > 1) - backend = lookup_type (argv[1]); - - if (argc > 2) - devname = argv[2]; -#endif - - // Set the default action. - if (!memory && !dives) { - memory = 1; - dives = 1; - } - - signal (SIGINT, sighandler); - - message_set_logfile (logfile); - - dc_context_t *context = NULL; - dc_status_t rc = dc_context_new (&context); - if (rc != DC_STATUS_SUCCESS) { - message_set_logfile (NULL); - return EXIT_FAILURE; - } - - dc_context_set_loglevel (context, loglevel); - dc_context_set_logfunc (context, logfunc, NULL); - - /* Search for a matching device descriptor. */ - dc_descriptor_t *descriptor = NULL; - rc = search (&descriptor, name, backend, model); - if (rc != DC_STATUS_SUCCESS) { - message_set_logfile (NULL); - return EXIT_FAILURE; - } - - /* Fail if no device descriptor found. */ - if (descriptor == NULL) { - WARNING ("No matching device found."); - usage (argv[0]); - message_set_logfile (NULL); - return EXIT_FAILURE; - } - - dc_buffer_t *fp = fpconvert (fingerprint); - rc = dowork (context, descriptor, devname, rawfile, xmlfile, memory, dives, fp); - dc_buffer_free (fp); - message ("Result: %s\n", errmsg (rc)); - - dc_descriptor_free (descriptor); - dc_context_free (context); - - message_set_logfile (NULL); - - return rc != DC_STATUS_SUCCESS ? EXIT_FAILURE : EXIT_SUCCESS; -}