diff --git a/examples/Makefile.am b/examples/Makefile.am index ddbade4..29f4bb6 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -5,6 +5,8 @@ bin_PROGRAMS = \ dctool dctool_SOURCES = \ + common.h \ + common.c \ dctool.h \ dctool.c \ utils.h \ diff --git a/examples/common.c b/examples/common.c new file mode 100644 index 0000000..6cb0867 --- /dev/null +++ b/examples/common.c @@ -0,0 +1,152 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include + +#include "common.h" +#include "utils.h" + +#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array)) + +typedef struct backend_table_t { + const char *name; + dc_family_t type; +} backend_table_t; + +static const backend_table_t g_backends[] = { + {"solution", DC_FAMILY_SUUNTO_SOLUTION}, + {"eon", DC_FAMILY_SUUNTO_EON}, + {"vyper", DC_FAMILY_SUUNTO_VYPER}, + {"vyper2", DC_FAMILY_SUUNTO_VYPER2}, + {"d9", DC_FAMILY_SUUNTO_D9}, + {"eonsteel", DC_FAMILY_SUUNTO_EONSTEEL}, + {"aladin", DC_FAMILY_UWATEC_ALADIN}, + {"memomouse", DC_FAMILY_UWATEC_MEMOMOUSE}, + {"smart", DC_FAMILY_UWATEC_SMART}, + {"meridian", DC_FAMILY_UWATEC_MERIDIAN}, + {"sensus", DC_FAMILY_REEFNET_SENSUS}, + {"sensuspro", DC_FAMILY_REEFNET_SENSUSPRO}, + {"sensusultra", DC_FAMILY_REEFNET_SENSUSULTRA}, + {"vtpro", DC_FAMILY_OCEANIC_VTPRO}, + {"veo250", DC_FAMILY_OCEANIC_VEO250}, + {"atom2", DC_FAMILY_OCEANIC_ATOM2}, + {"nemo", DC_FAMILY_MARES_NEMO}, + {"puck", DC_FAMILY_MARES_PUCK}, + {"darwin", DC_FAMILY_MARES_DARWIN}, + {"iconhd", DC_FAMILY_MARES_ICONHD}, + {"ostc", DC_FAMILY_HW_OSTC}, + {"frog", DC_FAMILY_HW_FROG}, + {"ostc3", DC_FAMILY_HW_OSTC3}, + {"edy", DC_FAMILY_CRESSI_EDY}, + {"leonardo", DC_FAMILY_CRESSI_LEONARDO}, + {"n2ition3", DC_FAMILY_ZEAGLE_N2ITION3}, + {"cobalt", DC_FAMILY_ATOMICS_COBALT}, + {"predator", DC_FAMILY_SHEARWATER_PREDATOR}, + {"petrel", DC_FAMILY_SHEARWATER_PETREL}, + {"nitekq", DC_FAMILY_DIVERITE_NITEKQ}, + {"aqualand", DC_FAMILY_CITIZEN_AQUALAND}, + {"idive", DC_FAMILY_DIVESYSTEM_IDIVE}, +}; + +dc_family_t +dctool_family_type (const char *name) +{ + for (unsigned int i = 0; i < C_ARRAY_SIZE (g_backends); ++i) { + if (strcmp (name, g_backends[i].name) == 0) + return g_backends[i].type; + } + + return DC_FAMILY_NULL; +} + +const char * +dctool_family_name (dc_family_t type) +{ + for (unsigned int i = 0; i < C_ARRAY_SIZE (g_backends); ++i) { + if (g_backends[i].type == type) + return g_backends[i].name; + } + + return NULL; +} + +dc_status_t +dctool_descriptor_search (dc_descriptor_t **out, const char *name, dc_family_t family, unsigned int model) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + + dc_iterator_t *iterator = NULL; + rc = dc_descriptor_iterator (&iterator); + if (rc != DC_STATUS_SUCCESS) { + ERROR ("Error creating the device descriptor iterator."); + return rc; + } + + dc_descriptor_t *descriptor = NULL, *current = NULL; + while ((rc = dc_iterator_next (iterator, &descriptor)) == DC_STATUS_SUCCESS) { + if (name) { + const char *vendor = dc_descriptor_get_vendor (descriptor); + const char *product = dc_descriptor_get_product (descriptor); + + size_t n = strlen (vendor); + if (strncasecmp (name, vendor, n) == 0 && name[n] == ' ' && + strcasecmp (name + n + 1, product) == 0) + { + current = descriptor; + break; + } else if (strcasecmp (name, product) == 0) { + current = descriptor; + break; + } + } else { + if (family == dc_descriptor_get_type (descriptor)) { + if (model == dc_descriptor_get_model (descriptor)) { + // Exact match found. Return immediately. + dc_descriptor_free (current); + current = descriptor; + break; + } else { + // Possible match found. Keep searching for an exact match. + // If no exact match is found, the first match is returned. + if (current == NULL) { + current = descriptor; + descriptor = NULL; + } + } + } + } + + dc_descriptor_free (descriptor); + } + + if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_DONE) { + dc_descriptor_free (current); + dc_iterator_free (iterator); + ERROR ("Error iterating the device descriptors."); + return rc; + } + + dc_iterator_free (iterator); + + *out = current; + + return DC_STATUS_SUCCESS; +} diff --git a/examples/common.h b/examples/common.h new file mode 100644 index 0000000..8393fd6 --- /dev/null +++ b/examples/common.h @@ -0,0 +1,45 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef DCTOOL_COMMON_H +#define DCTOOL_COMMON_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +dc_family_t +dctool_family_type (const char *name); + +const char * +dctool_family_name (dc_family_t type); + +dc_status_t +dctool_descriptor_search (dc_descriptor_t **out, const char *name, dc_family_t family, unsigned int model); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DCTOOL_COMMON_H */ diff --git a/examples/dctool.c b/examples/dctool.c index 501e33a..48f3687 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -31,6 +31,10 @@ #include #endif +#include +#include + +#include "common.h" #include "dctool.h" #include "utils.h" @@ -81,18 +85,25 @@ main (int argc, char *argv[]) int exitcode = EXIT_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS; dc_context_t *context = NULL; + dc_descriptor_t *descriptor = NULL; // Default option values. unsigned int help = 0; dc_loglevel_t loglevel = DC_LOGLEVEL_WARNING; const char *logfile = NULL; + const char *device = NULL; + dc_family_t family = DC_FAMILY_NULL; + unsigned int model = 0; // Parse the command-line options. int opt = 0; - const char *optstring = NOPERMUTATION "hl:qv"; + const char *optstring = NOPERMUTATION "hd:f:m:l:qv"; #ifdef HAVE_GETOPT_LONG struct option options[] = { {"help", no_argument, 0, 'h'}, + {"device", required_argument, 0, 'd'}, + {"family", required_argument, 0, 'f'}, + {"model", required_argument, 0, 'm'}, {"logfile", required_argument, 0, 'l'}, {"quiet", no_argument, 0, 'q'}, {"verbose", no_argument, 0, 'v'}, @@ -106,6 +117,15 @@ main (int argc, char *argv[]) case 'h': help = 1; break; + case 'd': + device = optarg; + break; + case 'f': + family = dctool_family_type (optarg); + break; + case 'm': + model = strtoul (optarg, NULL, 0); + break; case 'l': logfile = optarg; break; @@ -136,11 +156,17 @@ main (int argc, char *argv[]) "Options:\n" #ifdef HAVE_GETOPT_LONG " -h, --help Show help message\n" + " -d, --device Device name\n" + " -f, --family Device family type\n" + " -m, --model Device model number\n" " -l, --logfile Logfile\n" " -q, --quiet Quiet mode\n" " -v, --verbose Verbose mode\n" #else " -h Show help message\n" + " -d Device name\n" + " -f Family type\n" + " -m Model number\n" " -l Logfile\n" " -q Quiet mode\n" " -v Verbose mode\n" @@ -170,10 +196,40 @@ main (int argc, char *argv[]) dc_context_set_loglevel (context, loglevel); dc_context_set_logfunc (context, logfunc, NULL); + if (command->config & DCTOOL_CONFIG_DESCRIPTOR) { + // Check mandatory arguments. + if (device == NULL && family == DC_FAMILY_NULL) { + message ("No device name or family type specified.\n"); + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Search for a matching device descriptor. + status = dctool_descriptor_search (&descriptor, device, family, model); + if (status != DC_STATUS_SUCCESS) { + exitcode = EXIT_FAILURE; + goto cleanup; + } + + // Fail if no device descriptor found. + if (descriptor == NULL) { + if (device) { + message ("No supported device found: %s\n", + device); + } else { + message ("No supported device found: %s, 0x%X\n", + dctool_family_name (family), model); + } + exitcode = EXIT_FAILURE; + goto cleanup; + } + } + // Execute the command. - exitcode = command->run (argc, argv, context); + exitcode = command->run (argc, argv, context, descriptor); cleanup: + dc_descriptor_free (descriptor); dc_context_free (context); message_set_logfile (NULL); return exitcode; diff --git a/examples/dctool.h b/examples/dctool.h index db4f527..b091c83 100644 --- a/examples/dctool.h +++ b/examples/dctool.h @@ -23,13 +23,20 @@ #define DCTOOL_H #include +#include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ +typedef enum dctool_config_t { + DCTOOL_CONFIG_NONE = 0, + DCTOOL_CONFIG_DESCRIPTOR = 1, +} dctool_config_t; + typedef struct dctool_command_t { - int (*run) (int argc, char *argv[], dc_context_t *context); + int (*run) (int argc, char *argv[], dc_context_t *context, dc_descriptor_t *descriptor); + unsigned int config; const char *name; const char *description; const char *usage;