Merge branch 'dctool'

This commit is contained in:
Jef Driesen 2016-01-05 20:39:52 +01:00
commit 0fb6f5a7fa
17 changed files with 2371 additions and 1150 deletions

View File

@ -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])

View File

@ -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

View File

@ -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 <string.h>
#include <stdio.h>
#ifdef _WIN32
#include <io.h>
#include <fcntl.h>
#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;
}

View File

@ -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 <libdivecomputer/common.h>
#include <libdivecomputer/context.h>
#include <libdivecomputer/descriptor.h>
#include <libdivecomputer/device.h>
#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 */

295
examples/dctool.c Normal file
View File

@ -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 <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <libdivecomputer/context.h>
#include <libdivecomputer/descriptor.h>
#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] <command> [<args>]\n"
"\n"
"Options:\n"
#ifdef HAVE_GETOPT_LONG
" -h, --help Show help message\n"
" -d, --device <device> Device name\n"
" -f, --family <family> Device family type\n"
" -m, --model <model> Device model number\n"
" -l, --logfile <logfile> Logfile\n"
" -q, --quiet Quiet mode\n"
" -v, --verbose Verbose mode\n"
#else
" -h Show help message\n"
" -d <device> Device name\n"
" -f <family> Family type\n"
" -m <model> Model number\n"
" -l <logfile> 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 <command>' 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;
}

67
examples/dctool.h Normal file
View File

@ -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 <libdivecomputer/context.h>
#include <libdivecomputer/descriptor.h>
#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 */

616
examples/dctool_download.c Normal file
View File

@ -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 <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <libdivecomputer/context.h>
#include <libdivecomputer/descriptor.h>
#include <libdivecomputer/device.h>
#include <libdivecomputer/parser.h>
#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, "</sample>\n");
fprintf (sampledata->ostream, "<sample>\n");
fprintf (sampledata->ostream, " <time>%02u:%02u</time>\n", value.time / 60, value.time % 60);
break;
case DC_SAMPLE_DEPTH:
fprintf (sampledata->ostream, " <depth>%.2f</depth>\n", value.depth);
break;
case DC_SAMPLE_PRESSURE:
fprintf (sampledata->ostream, " <pressure tank=\"%u\">%.2f</pressure>\n", value.pressure.tank, value.pressure.value);
break;
case DC_SAMPLE_TEMPERATURE:
fprintf (sampledata->ostream, " <temperature>%.2f</temperature>\n", value.temperature);
break;
case DC_SAMPLE_EVENT:
if (value.event.type != SAMPLE_EVENT_GASCHANGE && value.event.type != SAMPLE_EVENT_GASCHANGE2) {
fprintf (sampledata->ostream, " <event type=\"%u\" time=\"%u\" flags=\"%u\" value=\"%u\">%s</event>\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, " <rbt>%u</rbt>\n", value.rbt);
break;
case DC_SAMPLE_HEARTBEAT:
fprintf (sampledata->ostream, " <heartbeat>%u</heartbeat>\n", value.heartbeat);
break;
case DC_SAMPLE_BEARING:
fprintf (sampledata->ostream, " <bearing>%u</bearing>\n", value.bearing);
break;
case DC_SAMPLE_VENDOR:
fprintf (sampledata->ostream, " <vendor type=\"%u\" size=\"%u\">", 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, "</vendor>\n");
break;
case DC_SAMPLE_SETPOINT:
fprintf (sampledata->ostream, " <setpoint>%.2f</setpoint>\n", value.setpoint);
break;
case DC_SAMPLE_PPO2:
fprintf (sampledata->ostream, " <ppo2>%.2f</ppo2>\n", value.ppo2);
break;
case DC_SAMPLE_CNS:
fprintf (sampledata->ostream, " <cns>%.1f</cns>\n", value.cns * 100.0);
break;
case DC_SAMPLE_DECO:
fprintf (sampledata->ostream, " <deco time=\"%u\" depth=\"%.2f\">%s</deco>\n",
value.deco.time, value.deco.depth, decostop[value.deco.type]);
break;
case DC_SAMPLE_GASMIX:
fprintf (sampledata->ostream, " <gasmix>%u</gasmix>\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, "<datetime>%04i-%02i-%02i %02i:%02i:%02i</datetime>\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, "<divetime>%02u:%02u</divetime>\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, "<maxdepth>%.2f</maxdepth>\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, "<temperature type=\"%s\">%.1f</temperature>\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,
"<gasmix>\n"
" <he>%.1f</he>\n"
" <o2>%.1f</o2>\n"
" <n2>%.1f</n2>\n"
"</gasmix>\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, "<tank>\n");
if (tank.gasmix != DC_GASMIX_UNKNOWN) {
fprintf (ostream,
" <gasmix>%u</gasmix>\n",
tank.gasmix);
}
if (tank.type != DC_TANKVOLUME_NONE) {
fprintf (ostream,
" <type>%s</type>\n"
" <volume>%.1f</volume>\n"
" <workpressure>%.2f</workpressure>\n",
names[tank.type], tank.volume, tank.workpressure);
}
fprintf (ostream,
" <beginpressure>%.2f</beginpressure>\n"
" <endpressure>%.2f</endpressure>\n"
"</tank>\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, "<divemode>%s</divemode>\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, "<salinity type=\"%u\">%.1f</salinity>\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, "<atmospheric>%.5f</atmospheric>\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, "</sample>\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, "<dive>\n<number>%u</number>\n<size>%u</size>\n<fingerprint>", divedata->number, size);
for (unsigned int i = 0; i < fsize; ++i)
fprintf (divedata->ostream, "%02X", fingerprint[i]);
fprintf (divedata->ostream, "</fingerprint>\n");
doparse (divedata->ostream, divedata->device, data, size);
fprintf (divedata->ostream, "</dive>\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, "<device>\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, "</device>\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] <devname>\n"
"\n"
"Options:\n"
#ifdef HAVE_GETOPT_LONG
" -h, --help Show help message\n"
" -o, --output <filename> Output filename\n"
" -p, --fingerprint <data> Fingerprint data (hexadecimal)\n"
" -c, --cache <directory> Cache directory\n"
#else
" -h Show help message\n"
" -o <filename> Output filename\n"
" -p <fingerprint> Fingerprint data (hexadecimal)\n"
" -c <directory> Cache directory\n"
#endif
};

191
examples/dctool_dump.c Normal file
View File

@ -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 <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <libdivecomputer/context.h>
#include <libdivecomputer/descriptor.h>
#include <libdivecomputer/device.h>
#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] <devname>\n"
"\n"
"Options:\n"
#ifdef HAVE_GETOPT_LONG
" -h, --help Show help message\n"
" -o, --output <filename> Output filename\n"
" -p, --fingerprint <data> Fingerprint data (hexadecimal)\n"
#else
" -h Show help message\n"
" -o <filename> Output filename\n"
" -p <fingerprint> Fingerprint data (hexadecimal)\n"
#endif
};

179
examples/dctool_fwupdate.c Normal file
View File

@ -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 <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <libdivecomputer/context.h>
#include <libdivecomputer/descriptor.h>
#include <libdivecomputer/device.h>
#include <libdivecomputer/hw_ostc.h>
#include <libdivecomputer/hw_ostc3.h>
#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 <filename> Firmware filename\n"
#else
" -h Show help message\n"
" -f <filename> Firmware filename\n"
#endif
};

105
examples/dctool_help.c Normal file
View File

@ -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 <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <libdivecomputer/context.h>
#include <libdivecomputer/descriptor.h>
#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] [<command>]\n"
"\n"
"Options:\n"
#ifdef HAVE_GETOPT_LONG
" -h, --help Show help message\n"
#else
" -h Show help message\n"
#endif
};

103
examples/dctool_list.c Normal file
View File

@ -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 <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <libdivecomputer/context.h>
#include <libdivecomputer/descriptor.h>
#include <libdivecomputer/iterator.h>
#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
};

197
examples/dctool_read.c Normal file
View File

@ -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 <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <libdivecomputer/context.h>
#include <libdivecomputer/descriptor.h>
#include <libdivecomputer/device.h>
#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] <devname>\n"
"\n"
"Options:\n"
#ifdef HAVE_GETOPT_LONG
" -h, --help Show help message\n"
" -a, --address <address> Memory address\n"
" -c, --count <count> Number of bytes\n"
" -o, --output <filename> Output filename\n"
#else
" -h Show help message\n"
" -a <address> Memory address\n"
" -c <count> Number of bytes\n"
" -o <filename> Output filename\n"
#endif
};

94
examples/dctool_version.c Normal file
View File

@ -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 <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <libdivecomputer/context.h>
#include <libdivecomputer/descriptor.h>
#include <libdivecomputer/version.h>
#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
};

200
examples/dctool_write.c Normal file
View File

@ -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 <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <libdivecomputer/context.h>
#include <libdivecomputer/descriptor.h>
#include <libdivecomputer/device.h>
#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] <devname>\n"
"\n"
"Options:\n"
#ifdef HAVE_GETOPT_LONG
" -h, --help Show help message\n"
" -a, --address <address> Memory address\n"
" -c, --count <count> Number of bytes\n"
" -i, --input <filename> Input filename\n"
#else
" -h Show help message\n"
" -a <address> Memory address\n"
" -c <count> Number of bytes\n"
" -i <filename> Input filename\n"
#endif
};

View File

@ -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 <string.h>
#include <libdivecomputer/hw_ostc.h>
#include <libdivecomputer/hw_ostc3.h>
#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;
}

View File

@ -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 <stdio.h> // fopen, fwrite, fclose
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#ifndef _MSC_VER
#include <unistd.h>
#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 <libdivecomputer/context.h>
#include <libdivecomputer/device.h>
#include <libdivecomputer/parser.h>
#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, "</sample>\n");
fprintf (sampledata->fp, "<sample>\n");
fprintf (sampledata->fp, " <time>%02u:%02u</time>\n", value.time / 60, value.time % 60);
break;
case DC_SAMPLE_DEPTH:
fprintf (sampledata->fp, " <depth>%.2f</depth>\n", value.depth);
break;
case DC_SAMPLE_PRESSURE:
fprintf (sampledata->fp, " <pressure tank=\"%u\">%.2f</pressure>\n", value.pressure.tank, value.pressure.value);
break;
case DC_SAMPLE_TEMPERATURE:
fprintf (sampledata->fp, " <temperature>%.2f</temperature>\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, " <event type=\"%u\" time=\"%u\" flags=\"%u\" value=\"%u\">%s</event>\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, " <rbt>%u</rbt>\n", value.rbt);
break;
case DC_SAMPLE_HEARTBEAT:
fprintf (sampledata->fp, " <heartbeat>%u</heartbeat>\n", value.heartbeat);
break;
case DC_SAMPLE_BEARING:
fprintf (sampledata->fp, " <bearing>%u</bearing>\n", value.bearing);
break;
case DC_SAMPLE_VENDOR:
fprintf (sampledata->fp, " <vendor type=\"%u\" size=\"%u\">", 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, "</vendor>\n");
break;
case DC_SAMPLE_SETPOINT:
fprintf (sampledata->fp, " <setpoint>%.2f</setpoint>\n", value.setpoint);
break;
case DC_SAMPLE_PPO2:
fprintf (sampledata->fp, " <ppo2>%.2f</ppo2>\n", value.ppo2);
break;
case DC_SAMPLE_CNS:
fprintf (sampledata->fp, " <cns>%.1f</cns>\n", value.cns * 100.0);
break;
case DC_SAMPLE_DECO:
fprintf (sampledata->fp, " <deco time=\"%u\" depth=\"%.2f\">%s</deco>\n",
value.deco.time, value.deco.depth, decostop[value.deco.type]);
break;
case DC_SAMPLE_GASMIX:
fprintf (sampledata->fp, " <gasmix>%u</gasmix>\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, "<datetime>%04i-%02i-%02i %02i:%02i:%02i</datetime>\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, "<divetime>%02u:%02u</divetime>\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, "<temperature type=\"%s\">%.1f</temperature>\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, "<maxdepth>%.2f</maxdepth>\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,
"<gasmix>\n"
" <he>%.1f</he>\n"
" <o2>%.1f</o2>\n"
" <n2>%.1f</n2>\n"
"</gasmix>\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, "<tank>\n");
if (tank.gasmix != DC_GASMIX_UNKNOWN) {
fprintf (fp,
" <gasmix>%u</gasmix>\n",
tank.gasmix);
}
if (tank.type != DC_TANKVOLUME_NONE) {
fprintf (fp,
" <type>%s</type>\n"
" <volume>%.1f</volume>\n"
" <workpressure>%.2f</workpressure>\n",
names[tank.type], tank.volume, tank.workpressure);
}
fprintf (fp,
" <beginpressure>%.2f</beginpressure>\n"
" <endpressure>%.2f</endpressure>\n"
"</tank>\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, "<divemode>%s</divemode>\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, "<salinity type=\"%u\">%.1f</salinity>\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, "<atmospheric>%.5f</atmospheric>\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, "</sample>\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, "<dive>\n<number>%u</number>\n<size>%u</size>\n<fingerprint>", divedata->number, size);
for (unsigned int i = 0; i < fsize; ++i)
fprintf (divedata->fp, "%02X", fingerprint[i]);
fprintf (divedata->fp, "</fingerprint>\n");
doparse (divedata->fp, divedata->device, data, size);
fprintf (divedata->fp, "</dive>\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, "<device>\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, "</device>\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;
}

View File

@ -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);