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..cb13b64 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -2,12 +2,20 @@ 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_read.c \ + dctool_write.c \ + dctool_fwupdate.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..4d70c0e --- /dev/null +++ b/examples/dctool.c @@ -0,0 +1,295 @@ +/* + * 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 + +#include +#include + +#include "common.h" +#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[] = { + &dctool_help, + &dctool_version, + &dctool_list, + &dctool_download, + &dctool_dump, + &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; + + // 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..a0e09d7 --- /dev/null +++ b/examples/dctool.h @@ -0,0 +1,67 @@ +/* + * 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_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..61c4127 --- /dev/null +++ b/examples/dctool_download.c @@ -0,0 +1,616 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif + +#include +#include +#include +#include + +#include "dctool.h" +#include "common.h" +#include "utils.h" + +typedef struct event_data_t { + const char *cachedir; + dc_event_devinfo_t devinfo; +} event_data_t; + +typedef struct dive_data_t { + FILE* ostream; + dc_device_t *device; + dc_buffer_t **fingerprint; + unsigned int number; +} dive_data_t; + +typedef struct sample_data_t { + FILE* ostream; + unsigned int nsamples; +} sample_data_t; + +static void +sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata) +{ + static const char *events[] = { + "none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter", + "violation", "bookmark", "surface", "safety stop", "gaschange", + "safety stop (voluntary)", "safety stop (mandatory)", "deepstop", + "ceiling (safety stop)", "floor", "divetime", "maxdepth", + "OLF", "PO2", "airtime", "rgbm", "heading", "tissue level warning", + "gaschange2"}; + static const char *decostop[] = { + "ndl", "safety", "deco", "deep"}; + + sample_data_t *sampledata = (sample_data_t *) userdata; + + switch (type) { + case DC_SAMPLE_TIME: + if (sampledata->nsamples++) + fprintf (sampledata->ostream, "\n"); + fprintf (sampledata->ostream, "\n"); + fprintf (sampledata->ostream, " \n", value.time / 60, value.time % 60); + break; + case DC_SAMPLE_DEPTH: + fprintf (sampledata->ostream, " %.2f\n", value.depth); + break; + case DC_SAMPLE_PRESSURE: + fprintf (sampledata->ostream, " %.2f\n", value.pressure.tank, value.pressure.value); + break; + case DC_SAMPLE_TEMPERATURE: + fprintf (sampledata->ostream, " %.2f\n", value.temperature); + break; + case DC_SAMPLE_EVENT: + if (value.event.type != SAMPLE_EVENT_GASCHANGE && value.event.type != SAMPLE_EVENT_GASCHANGE2) { + fprintf (sampledata->ostream, " %s\n", + value.event.type, value.event.time, value.event.flags, value.event.value, events[value.event.type]); + } + break; + case DC_SAMPLE_RBT: + fprintf (sampledata->ostream, " %u\n", value.rbt); + break; + case DC_SAMPLE_HEARTBEAT: + fprintf (sampledata->ostream, " %u\n", value.heartbeat); + break; + case DC_SAMPLE_BEARING: + fprintf (sampledata->ostream, " %u\n", value.bearing); + break; + case DC_SAMPLE_VENDOR: + fprintf (sampledata->ostream, " ", value.vendor.type, value.vendor.size); + for (unsigned int i = 0; i < value.vendor.size; ++i) + fprintf (sampledata->ostream, "%02X", ((unsigned char *) value.vendor.data)[i]); + fprintf (sampledata->ostream, "\n"); + break; + case DC_SAMPLE_SETPOINT: + fprintf (sampledata->ostream, " %.2f\n", value.setpoint); + break; + case DC_SAMPLE_PPO2: + fprintf (sampledata->ostream, " %.2f\n", value.ppo2); + break; + case DC_SAMPLE_CNS: + fprintf (sampledata->ostream, " %.1f\n", value.cns * 100.0); + break; + case DC_SAMPLE_DECO: + fprintf (sampledata->ostream, " %s\n", + value.deco.time, value.deco.depth, decostop[value.deco.type]); + break; + case DC_SAMPLE_GASMIX: + fprintf (sampledata->ostream, " %u\n", value.gasmix); + break; + default: + break; + } +} + +static dc_status_t +doparse (FILE *ostream, dc_device_t *device, const unsigned char data[], unsigned int size) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + dc_parser_t *parser = NULL; + + // Create the parser. + message ("Creating the parser.\n"); + rc = dc_parser_new (&parser, device); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error creating the parser."); + goto cleanup; + } + + // Register the data. + message ("Registering the data.\n"); + rc = dc_parser_set_data (parser, data, size); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the data."); + goto cleanup; + } + + // Parse the datetime. + message ("Parsing the datetime.\n"); + dc_datetime_t dt = {0}; + rc = dc_parser_get_datetime (parser, &dt); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the datetime."); + goto cleanup; + } + + fprintf (ostream, "%04i-%02i-%02i %02i:%02i:%02i\n", + dt.year, dt.month, dt.day, + dt.hour, dt.minute, dt.second); + + // Parse the divetime. + message ("Parsing the divetime.\n"); + unsigned int divetime = 0; + rc = dc_parser_get_field (parser, DC_FIELD_DIVETIME, 0, &divetime); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the divetime."); + goto cleanup; + } + + fprintf (ostream, "%02u:%02u\n", + divetime / 60, divetime % 60); + + // Parse the maxdepth. + message ("Parsing the maxdepth.\n"); + double maxdepth = 0.0; + rc = dc_parser_get_field (parser, DC_FIELD_MAXDEPTH, 0, &maxdepth); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the maxdepth."); + goto cleanup; + } + + fprintf (ostream, "%.2f\n", + maxdepth); + + // Parse the temperature. + message ("Parsing the temperature.\n"); + for (unsigned int i = 0; i < 3; ++i) { + dc_field_type_t fields[] = {DC_FIELD_TEMPERATURE_SURFACE, + DC_FIELD_TEMPERATURE_MINIMUM, + DC_FIELD_TEMPERATURE_MAXIMUM}; + const char *names[] = {"surface", "minimum", "maximum"}; + + double temperature = 0.0; + rc = dc_parser_get_field (parser, fields[i], 0, &temperature); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the temperature."); + goto cleanup; + } + + if (rc != DC_STATUS_UNSUPPORTED) { + fprintf (ostream, "%.1f\n", + names[i], temperature); + } + } + + // Parse the gas mixes. + message ("Parsing the gas mixes.\n"); + unsigned int ngases = 0; + rc = dc_parser_get_field (parser, DC_FIELD_GASMIX_COUNT, 0, &ngases); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the gas mix count."); + goto cleanup; + } + + for (unsigned int i = 0; i < ngases; ++i) { + dc_gasmix_t gasmix = {0}; + rc = dc_parser_get_field (parser, DC_FIELD_GASMIX, i, &gasmix); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the gas mix."); + goto cleanup; + } + + fprintf (ostream, + "\n" + " %.1f\n" + " %.1f\n" + " %.1f\n" + "\n", + gasmix.helium * 100.0, + gasmix.oxygen * 100.0, + gasmix.nitrogen * 100.0); + } + + // Parse the tanks. + message ("Parsing the tanks.\n"); + unsigned int ntanks = 0; + rc = dc_parser_get_field (parser, DC_FIELD_TANK_COUNT, 0, &ntanks); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the tank count."); + goto cleanup; + } + + for (unsigned int i = 0; i < ntanks; ++i) { + const char *names[] = {"none", "metric", "imperial"}; + + dc_tank_t tank = {0}; + rc = dc_parser_get_field (parser, DC_FIELD_TANK, i, &tank); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the tank."); + goto cleanup; + } + + fprintf (ostream, "\n"); + if (tank.gasmix != DC_GASMIX_UNKNOWN) { + fprintf (ostream, + " %u\n", + tank.gasmix); + } + if (tank.type != DC_TANKVOLUME_NONE) { + fprintf (ostream, + " %s\n" + " %.1f\n" + " %.2f\n", + names[tank.type], tank.volume, tank.workpressure); + } + fprintf (ostream, + " %.2f\n" + " %.2f\n" + "\n", + tank.beginpressure, tank.endpressure); + } + + // Parse the dive mode. + message ("Parsing the dive mode.\n"); + dc_divemode_t divemode = DC_DIVEMODE_OC; + rc = dc_parser_get_field (parser, DC_FIELD_DIVEMODE, 0, &divemode); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the dive mode."); + goto cleanup; + } + + if (rc != DC_STATUS_UNSUPPORTED) { + const char *names[] = {"freedive", "gauge", "oc", "cc"}; + fprintf (ostream, "%s\n", + names[divemode]); + } + + // Parse the salinity. + message ("Parsing the salinity.\n"); + dc_salinity_t salinity = {DC_WATER_FRESH, 0.0}; + rc = dc_parser_get_field (parser, DC_FIELD_SALINITY, 0, &salinity); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the salinity."); + goto cleanup; + } + + if (rc != DC_STATUS_UNSUPPORTED) { + fprintf (ostream, "%.1f\n", + salinity.type, salinity.density); + } + + // Parse the atmospheric pressure. + message ("Parsing the atmospheric pressure.\n"); + double atmospheric = 0.0; + rc = dc_parser_get_field (parser, DC_FIELD_ATMOSPHERIC, 0, &atmospheric); + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { + ERROR ("Error parsing the atmospheric pressure."); + goto cleanup; + } + + if (rc != DC_STATUS_UNSUPPORTED) { + fprintf (ostream, "%.5f\n", + atmospheric); + } + + // Initialize the sample data. + sample_data_t sampledata = {0}; + sampledata.nsamples = 0; + sampledata.ostream = ostream; + + // Parse the sample data. + message ("Parsing the sample data.\n"); + rc = dc_parser_samples_foreach (parser, sample_cb, &sampledata); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error parsing the sample data."); + goto cleanup; + } + + if (sampledata.nsamples) + fprintf (ostream, "\n"); + +cleanup: + dc_parser_destroy (parser); + return rc; +} + +static int +dive_cb (const unsigned char *data, unsigned int size, const unsigned char *fingerprint, unsigned int fsize, void *userdata) +{ + dive_data_t *divedata = (dive_data_t *) userdata; + + divedata->number++; + + message ("Dive: number=%u, size=%u, fingerprint=", divedata->number, size); + for (unsigned int i = 0; i < fsize; ++i) + message ("%02X", fingerprint[i]); + message ("\n"); + + // Keep a copy of the most recent fingerprint. Because dives are + // guaranteed to be downloaded in reverse order, the most recent + // dive is always the first dive. + if (divedata->number == 1) { + dc_buffer_t *fp = dc_buffer_new (fsize); + dc_buffer_append (fp, fingerprint, fsize); + *divedata->fingerprint = fp; + } + + fprintf (divedata->ostream, "\n%u\n%u\n", divedata->number, size); + for (unsigned int i = 0; i < fsize; ++i) + fprintf (divedata->ostream, "%02X", fingerprint[i]); + fprintf (divedata->ostream, "\n"); + + doparse (divedata->ostream, divedata->device, data, size); + + fprintf (divedata->ostream, "\n"); + + return 1; +} + +static void +event_cb (dc_device_t *device, dc_event_type_t event, const void *data, void *userdata) +{ + const dc_event_devinfo_t *devinfo = (const dc_event_devinfo_t *) data; + + event_data_t *eventdata = (event_data_t *) userdata; + + // Forward to the default event handler. + dctool_event_cb (device, event, data, userdata); + + switch (event) { + case DC_EVENT_DEVINFO: + // Load the fingerprint from the cache. If there is no + // fingerprint present in the cache, a NULL buffer is returned, + // and the registered fingerprint will be cleared. + if (eventdata->cachedir) { + char filename[1024] = {0}; + dc_family_t family = DC_FAMILY_NULL; + dc_buffer_t *fingerprint = NULL; + + // Generate the fingerprint filename. + family = dc_device_get_type (device); + snprintf (filename, sizeof (filename), "%s/%s-%08X.bin", + eventdata->cachedir, dctool_family_name (family), devinfo->serial); + + // Read the fingerprint file. + fingerprint = dctool_file_read (filename); + + // Register the fingerprint data. + dc_device_set_fingerprint (device, + dc_buffer_get_data (fingerprint), + dc_buffer_get_size (fingerprint)); + + // Free the buffer again. + dc_buffer_free (fingerprint); + } + + // Keep a copy of the event data. It will be used for generating + // the fingerprint filename again after a (successful) download. + eventdata->devinfo = *devinfo; + break; + default: + break; + } +} + +static dc_status_t +download (dc_context_t *context, dc_descriptor_t *descriptor, const char *devname, const char *cachedir, dc_buffer_t *fingerprint, FILE *ostream) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + dc_device_t *device = NULL; + dc_buffer_t *ofingerprint = NULL; + + // Open the device. + message ("Opening the device (%s %s, %s).\n", + dc_descriptor_get_vendor (descriptor), + dc_descriptor_get_product (descriptor), + devname ? devname : "null"); + rc = dc_device_open (&device, context, descriptor, devname); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error opening the device."); + goto cleanup; + } + + // Initialize the event data. + event_data_t eventdata = {0}; + if (fingerprint) { + eventdata.cachedir = NULL; + } else { + eventdata.cachedir = cachedir; + } + + // Register the event handler. + message ("Registering the event handler.\n"); + int events = DC_EVENT_WAITING | DC_EVENT_PROGRESS | DC_EVENT_DEVINFO | DC_EVENT_CLOCK | DC_EVENT_VENDOR; + rc = dc_device_set_events (device, events, event_cb, &eventdata); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the event handler."); + goto cleanup; + } + + // Register the cancellation handler. + message ("Registering the cancellation handler.\n"); + rc = dc_device_set_cancel (device, dctool_cancel_cb, NULL); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the cancellation handler."); + goto cleanup; + } + + // Register the fingerprint data. + if (fingerprint) { + message ("Registering the fingerprint data.\n"); + rc = dc_device_set_fingerprint (device, dc_buffer_get_data (fingerprint), dc_buffer_get_size (fingerprint)); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error registering the fingerprint data."); + goto cleanup; + } + } + + // Initialize the dive data. + dive_data_t divedata = {0}; + divedata.device = device; + divedata.ostream = ostream; + divedata.fingerprint = &ofingerprint; + divedata.number = 0; + + fprintf (ostream, "\n"); + + // Download the dives. + message ("Downloading the dives.\n"); + rc = dc_device_foreach (device, dive_cb, &divedata); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error downloading the dives."); + goto cleanup; + } + + fprintf (ostream, "\n"); + + // Store the fingerprint data. + if (cachedir && ofingerprint) { + char filename[1024] = {0}; + dc_family_t family = DC_FAMILY_NULL; + + // Generate the fingerprint filename. + family = dc_device_get_type (device); + snprintf (filename, sizeof (filename), "%s/%s-%08X.bin", + cachedir, dctool_family_name (family), eventdata.devinfo.serial); + + // Write the fingerprint file. + dctool_file_write (filename, ofingerprint); + } + +cleanup: + dc_buffer_free (ofingerprint); + dc_device_close (device); + return rc; +} + +static int +dctool_download_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t *descriptor) +{ + int exitcode = EXIT_SUCCESS; + dc_status_t status = DC_STATUS_SUCCESS; + dc_buffer_t *fingerprint = NULL; + FILE *ostream = NULL; + + // Default option values. + unsigned int help = 0; + const char *fphex = NULL; + const char *filename = NULL; + const char *cachedir = NULL; + + // Parse the command-line options. + int opt = 0; + const char *optstring = "ho:p:c:"; +#ifdef HAVE_GETOPT_LONG + struct option options[] = { + {"help", no_argument, 0, 'h'}, + {"output", required_argument, 0, 'o'}, + {"fingerprint", required_argument, 0, 'p'}, + {"cache", required_argument, 0, 'c'}, + {0, 0, 0, 0 } + }; + while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { +#else + while ((opt = getopt (argc, argv, optstring)) != -1) { +#endif + switch (opt) { + case 'h': + help = 1; + break; + case 'o': + filename = optarg; + break; + case 'p': + fphex = optarg; + break; + case 'c': + cachedir = optarg; + break; + default: + return EXIT_FAILURE; + } + } + + argc -= optind; + argv += optind; + + // Show help message. + if (help) { + dctool_command_showhelp (&dctool_download); + return EXIT_SUCCESS; + } + + // Convert the fingerprint to binary. + fingerprint = dctool_convert_hex2bin (fphex); + + // Open the output file. + ostream = fopen (filename, "w"); + if (ostream == NULL) { + message ("Failed to open the output file.\n"); + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Download the dives. + status = download (context, descriptor, argv[0], cachedir, fingerprint, ostream); + if (status != DC_STATUS_SUCCESS) { + message ("ERROR: %s\n", dctool_errmsg (status)); + exitcode = EXIT_FAILURE; + goto cleanup; + } + +cleanup: + if (ostream) fclose (ostream); + dc_buffer_free (fingerprint); + return exitcode; +} + +const dctool_command_t dctool_download = { + dctool_download_run, + DCTOOL_CONFIG_DESCRIPTOR, + "download", + "Download the dives", + "Usage:\n" + " dctool download [options] \n" + "\n" + "Options:\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help Show help message\n" + " -o, --output Output filename\n" + " -p, --fingerprint Fingerprint data (hexadecimal)\n" + " -c, --cache Cache directory\n" +#else + " -h Show help message\n" + " -o Output filename\n" + " -p Fingerprint data (hexadecimal)\n" + " -c Cache directory\n" +#endif +}; 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_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/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; -} 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);