Merge branch 'master' into Subsurface-branch

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
Dirk Hohndel 2016-02-27 21:33:02 +01:00
commit 7c33c633fb
103 changed files with 4721 additions and 2426 deletions

View File

@ -112,10 +112,16 @@ AM_CONDITIONAL([IRDA], [test "$irda_win32" = "yes" || test "$irda_linux" = "yes"
# Checks for header files.
AC_CHECK_HEADERS([linux/serial.h])
AC_CHECK_HEADERS([IOKit/serial/ioss.h])
AC_CHECK_HEADERS([getopt.h])
AC_CHECK_HEADERS([sys/param.h])
# Checks for global variable declarations.
AC_CHECK_DECLS([optreset])
# Checks for library functions.
AC_FUNC_STRERROR_R
AC_CHECK_FUNCS([localtime_r gmtime_r])
AC_CHECK_FUNCS([getopt_long])
# Versioning.
AC_SUBST([DC_VERSION],[dc_version])

View File

@ -2,12 +2,26 @@ AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
LDADD = $(top_builddir)/src/libdivecomputer.la
bin_PROGRAMS = \
universal \
ostc-fwupdate
dctool
COMMON = common.c common.h \
utils.c utils.h
universal_SOURCES = universal.c $(COMMON)
ostc_fwupdate_SOURCES = hw_ostc_fwupdate.c $(COMMON)
dctool_SOURCES = \
common.h \
common.c \
dctool.h \
dctool.c \
dctool_help.c \
dctool_version.c \
dctool_list.c \
dctool_download.c \
dctool_dump.c \
dctool_parse.c \
dctool_read.c \
dctool_write.c \
dctool_fwupdate.c \
output.h \
output-private.h \
output.c \
output_xml.c \
output_raw.c \
utils.h \
utils.c

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 */

306
examples/dctool.c Normal file
View File

@ -0,0 +1,306 @@
/*
* libdivecomputer
*
* Copyright (C) 2015 Jef Driesen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.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 RESET 0
#else
#define RESET 1
#endif
#if defined(__GLIBC__) || defined(__MINGW32__) || defined(BSD)
#define NOPERMUTATION "+"
#else
#define NOPERMUTATION ""
#endif
static const dctool_command_t *g_commands[] = {
&dctool_help,
&dctool_version,
&dctool_list,
&dctool_download,
&dctool_dump,
&dctool_parse,
&dctool_read,
&dctool_write,
&dctool_fwupdate,
NULL
};
static volatile sig_atomic_t g_cancel = 0;
const dctool_command_t *
dctool_command_find (const char *name)
{
if (name == NULL)
return NULL;
size_t i = 0;
while (g_commands[i] != NULL) {
if (strcmp(g_commands[i]->name, name) == 0) {
break;
}
i++;
}
return g_commands[i];
}
void
dctool_command_showhelp (const dctool_command_t *command)
{
if (command == NULL) {
unsigned int maxlength = 0;
for (size_t i = 0; g_commands[i] != NULL; ++i) {
unsigned int length = strlen (g_commands[i]->name);
if (length > maxlength)
maxlength = length;
}
printf (
"A simple command line interface for the libdivecomputer library\n"
"\n"
"Usage:\n"
" dctool [options] <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;
#if defined(HAVE_DECL_OPTRESET) && HAVE_DECL_OPTRESET
optreset = 1;
#endif
// Translate the help option into a command.
char *argv_help[] = {(char *) "help", NULL, NULL};
if (help || argv[0] == NULL) {
if (argv[0]) {
argv_help[1] = argv[0];
argv = argv_help;
argc = 2;
} else {
argv = argv_help;
argc = 1;
}
}
// Try to find the command.
const dctool_command_t *command = dctool_command_find (argv[0]);
if (command == NULL) {
message ("Unknown command %s.\n", argv[0]);
return EXIT_FAILURE;
}
// Setup the cancel signal handler.
signal (SIGINT, sighandler);
// Initialize the logfile.
message_set_logfile (logfile);
// Initialize a library context.
status = dc_context_new (&context);
if (status != DC_STATUS_SUCCESS) {
exitcode = EXIT_FAILURE;
goto cleanup;
}
// Setup the logging.
dc_context_set_loglevel (context, loglevel);
dc_context_set_logfunc (context, logfunc, NULL);
if (command->config & DCTOOL_CONFIG_DESCRIPTOR) {
// Check mandatory arguments.
if (device == NULL && family == DC_FAMILY_NULL) {
message ("No device name or family type specified.\n");
exitcode = EXIT_FAILURE;
goto cleanup;
}
// Search for a matching device descriptor.
status = dctool_descriptor_search (&descriptor, device, family, model);
if (status != DC_STATUS_SUCCESS) {
exitcode = EXIT_FAILURE;
goto cleanup;
}
// Fail if no device descriptor found.
if (descriptor == NULL) {
if (device) {
message ("No supported device found: %s\n",
device);
} else {
message ("No supported device found: %s, 0x%X\n",
dctool_family_name (family), model);
}
exitcode = EXIT_FAILURE;
goto cleanup;
}
}
// Execute the command.
exitcode = command->run (argc, argv, context, descriptor);
cleanup:
dc_descriptor_free (descriptor);
dc_context_free (context);
message_set_logfile (NULL);
return exitcode;
}

68
examples/dctool.h Normal file
View File

@ -0,0 +1,68 @@
/*
* libdivecomputer
*
* Copyright (C) 2015 Jef Driesen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef DCTOOL_H
#define DCTOOL_H
#include <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_parse;
extern const dctool_command_t dctool_read;
extern const dctool_command_t dctool_write;
extern const dctool_command_t dctool_fwupdate;
const dctool_command_t *
dctool_command_find (const char *name);
void
dctool_command_showhelp (const dctool_command_t *command);
int
dctool_cancel_cb (void *userdata);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* DCTOOL_H */

376
examples/dctool_download.c Normal file
View File

@ -0,0 +1,376 @@
/*
* libdivecomputer
*
* Copyright (C) 2015 Jef Driesen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <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 "output.h"
#include "utils.h"
typedef struct event_data_t {
const char *cachedir;
dc_event_devinfo_t devinfo;
} event_data_t;
typedef struct dive_data_t {
dc_device_t *device;
dc_buffer_t **fingerprint;
unsigned int number;
dctool_output_t *output;
} dive_data_t;
static int
dive_cb (const unsigned char *data, unsigned int size, const unsigned char *fingerprint, unsigned int fsize, void *userdata)
{
dive_data_t *divedata = (dive_data_t *) userdata;
dc_status_t rc = DC_STATUS_SUCCESS;
dc_parser_t *parser = NULL;
divedata->number++;
message ("Dive: number=%u, size=%u, fingerprint=", divedata->number, size);
for (unsigned int i = 0; i < fsize; ++i)
message ("%02X", fingerprint[i]);
message ("\n");
// Keep a copy of the most recent fingerprint. Because dives are
// guaranteed to be downloaded in reverse order, the most recent
// dive is always the first dive.
if (divedata->number == 1) {
dc_buffer_t *fp = dc_buffer_new (fsize);
dc_buffer_append (fp, fingerprint, fsize);
*divedata->fingerprint = fp;
}
// Create the parser.
message ("Creating the parser.\n");
rc = dc_parser_new (&parser, divedata->device);
if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error creating the parser.");
goto cleanup;
}
// Register the data.
message ("Registering the data.\n");
rc = dc_parser_set_data (parser, data, size);
if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error registering the data.");
goto cleanup;
}
// Parse the dive data.
message ("Parsing the dive data.\n");
rc = dctool_output_write (divedata->output, parser, data, size, fingerprint, fsize);
if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error parsing the dive data.");
goto cleanup;
}
cleanup:
dc_parser_destroy (parser);
return 1;
}
static void
event_cb (dc_device_t *device, dc_event_type_t event, const void *data, void *userdata)
{
const dc_event_devinfo_t *devinfo = (const dc_event_devinfo_t *) data;
event_data_t *eventdata = (event_data_t *) userdata;
// Forward to the default event handler.
dctool_event_cb (device, event, data, userdata);
switch (event) {
case DC_EVENT_DEVINFO:
// Load the fingerprint from the cache. If there is no
// fingerprint present in the cache, a NULL buffer is returned,
// and the registered fingerprint will be cleared.
if (eventdata->cachedir) {
char filename[1024] = {0};
dc_family_t family = DC_FAMILY_NULL;
dc_buffer_t *fingerprint = NULL;
// Generate the fingerprint filename.
family = dc_device_get_type (device);
snprintf (filename, sizeof (filename), "%s/%s-%08X.bin",
eventdata->cachedir, dctool_family_name (family), devinfo->serial);
// Read the fingerprint file.
fingerprint = dctool_file_read (filename);
// Register the fingerprint data.
dc_device_set_fingerprint (device,
dc_buffer_get_data (fingerprint),
dc_buffer_get_size (fingerprint));
// Free the buffer again.
dc_buffer_free (fingerprint);
}
// Keep a copy of the event data. It will be used for generating
// the fingerprint filename again after a (successful) download.
eventdata->devinfo = *devinfo;
break;
default:
break;
}
}
static dc_status_t
download (dc_context_t *context, dc_descriptor_t *descriptor, const char *devname, const char *cachedir, dc_buffer_t *fingerprint, dctool_output_t *output)
{
dc_status_t rc = DC_STATUS_SUCCESS;
dc_device_t *device = NULL;
dc_buffer_t *ofingerprint = NULL;
// Open the device.
message ("Opening the device (%s %s, %s).\n",
dc_descriptor_get_vendor (descriptor),
dc_descriptor_get_product (descriptor),
devname ? devname : "null");
rc = dc_device_open (&device, context, descriptor, devname);
if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error opening the device.");
goto cleanup;
}
// Initialize the event data.
event_data_t eventdata = {0};
if (fingerprint) {
eventdata.cachedir = NULL;
} else {
eventdata.cachedir = cachedir;
}
// Register the event handler.
message ("Registering the event handler.\n");
int events = DC_EVENT_WAITING | DC_EVENT_PROGRESS | DC_EVENT_DEVINFO | DC_EVENT_CLOCK | DC_EVENT_VENDOR;
rc = dc_device_set_events (device, events, event_cb, &eventdata);
if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error registering the event handler.");
goto cleanup;
}
// Register the cancellation handler.
message ("Registering the cancellation handler.\n");
rc = dc_device_set_cancel (device, dctool_cancel_cb, NULL);
if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error registering the cancellation handler.");
goto cleanup;
}
// Register the fingerprint data.
if (fingerprint) {
message ("Registering the fingerprint data.\n");
rc = dc_device_set_fingerprint (device, dc_buffer_get_data (fingerprint), dc_buffer_get_size (fingerprint));
if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error registering the fingerprint data.");
goto cleanup;
}
}
// Initialize the dive data.
dive_data_t divedata = {0};
divedata.device = device;
divedata.fingerprint = &ofingerprint;
divedata.number = 0;
divedata.output = output;
// Download the dives.
message ("Downloading the dives.\n");
rc = dc_device_foreach (device, dive_cb, &divedata);
if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error downloading the dives.");
goto cleanup;
}
// Store the fingerprint data.
if (cachedir && ofingerprint) {
char filename[1024] = {0};
dc_family_t family = DC_FAMILY_NULL;
// Generate the fingerprint filename.
family = dc_device_get_type (device);
snprintf (filename, sizeof (filename), "%s/%s-%08X.bin",
cachedir, dctool_family_name (family), eventdata.devinfo.serial);
// Write the fingerprint file.
dctool_file_write (filename, ofingerprint);
}
cleanup:
dc_buffer_free (ofingerprint);
dc_device_close (device);
return rc;
}
static int
dctool_download_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t *descriptor)
{
int exitcode = EXIT_SUCCESS;
dc_status_t status = DC_STATUS_SUCCESS;
dc_buffer_t *fingerprint = NULL;
dctool_output_t *output = NULL;
// Default option values.
unsigned int help = 0;
const char *fphex = NULL;
const char *filename = NULL;
const char *cachedir = NULL;
const char *format = "xml";
// Parse the command-line options.
int opt = 0;
const char *optstring = "ho:p:c:f:";
#ifdef HAVE_GETOPT_LONG
struct option options[] = {
{"help", no_argument, 0, 'h'},
{"output", required_argument, 0, 'o'},
{"fingerprint", required_argument, 0, 'p'},
{"cache", required_argument, 0, 'c'},
{"format", required_argument, 0, 'f'},
{0, 0, 0, 0 }
};
while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) {
#else
while ((opt = getopt (argc, argv, optstring)) != -1) {
#endif
switch (opt) {
case 'h':
help = 1;
break;
case 'o':
filename = optarg;
break;
case 'p':
fphex = optarg;
break;
case 'c':
cachedir = optarg;
break;
case 'f':
format = optarg;
break;
default:
return EXIT_FAILURE;
}
}
argc -= optind;
argv += optind;
// Show help message.
if (help) {
dctool_command_showhelp (&dctool_download);
return EXIT_SUCCESS;
}
// Convert the fingerprint to binary.
fingerprint = dctool_convert_hex2bin (fphex);
// Create the output.
if (strcasecmp(format, "raw") == 0) {
output = dctool_raw_output_new (filename);
} else if (strcasecmp(format, "xml") == 0) {
output = dctool_xml_output_new (filename);
} else {
message ("Unknown output format: %s\n", format);
exitcode = EXIT_FAILURE;
goto cleanup;
}
if (output == NULL) {
message ("Failed to create the output.\n");
exitcode = EXIT_FAILURE;
goto cleanup;
}
// Download the dives.
status = download (context, descriptor, argv[0], cachedir, fingerprint, output);
if (status != DC_STATUS_SUCCESS) {
message ("ERROR: %s\n", dctool_errmsg (status));
exitcode = EXIT_FAILURE;
goto cleanup;
}
cleanup:
dctool_output_free (output);
dc_buffer_free (fingerprint);
return exitcode;
}
const dctool_command_t dctool_download = {
dctool_download_run,
DCTOOL_CONFIG_DESCRIPTOR,
"download",
"Download the dives",
"Usage:\n"
" dctool download [options] <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"
" -f, --format <format> Output format\n"
#else
" -h Show help message\n"
" -o <filename> Output filename\n"
" -p <fingerprint> Fingerprint data (hexadecimal)\n"
" -c <directory> Cache directory\n"
" -f <format> Output format\n"
#endif
"\n"
"Supported output formats:\n"
"\n"
" XML (default)\n"
"\n"
" All dives are exported to a single xml file.\n"
"\n"
" RAW\n"
"\n"
" Each dive is exported to a raw (binary) file. To output multiple\n"
" files, the filename is interpreted as a template and should\n"
" contain one or more placeholders.\n"
"\n"
"Supported template placeholders:\n"
"\n"
" %f Fingerprint (hexadecimal format)\n"
" %n Number (4 digits)\n"
" %t Timestamp (basic ISO 8601 date/time format)\n"
};

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
};

304
examples/dctool_parse.c Normal file
View File

@ -0,0 +1,304 @@
/*
* libdivecomputer
*
* Copyright (C) 2015 Jef Driesen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <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/parser.h>
#include <libdivecomputer/suunto.h>
#include <libdivecomputer/reefnet.h>
#include <libdivecomputer/uwatec.h>
#include <libdivecomputer/oceanic.h>
#include <libdivecomputer/mares.h>
#include <libdivecomputer/hw.h>
#include <libdivecomputer/cressi.h>
#include <libdivecomputer/zeagle.h>
#include <libdivecomputer/atomics.h>
#include <libdivecomputer/shearwater.h>
#include <libdivecomputer/diverite.h>
#include <libdivecomputer/citizen.h>
#include <libdivecomputer/divesystem.h>
#include "dctool.h"
#include "output.h"
#include "common.h"
#include "utils.h"
#define REACTPROWHITE 0x4354
static dc_status_t
parse (dc_buffer_t *buffer, dc_context_t *context, dc_descriptor_t *descriptor, unsigned int devtime, dc_ticks_t systime, dctool_output_t *output)
{
dc_status_t rc = DC_STATUS_SUCCESS;
dc_parser_t *parser = NULL;
dc_family_t family = dc_descriptor_get_type (descriptor);
unsigned int model = dc_descriptor_get_model (descriptor);
unsigned char *data = dc_buffer_get_data (buffer);
unsigned int size = dc_buffer_get_size (buffer);
// Create the parser.
message ("Creating the parser.\n");
switch (family) {
case DC_FAMILY_SUUNTO_SOLUTION:
rc = suunto_solution_parser_create (&parser, context);
break;
case DC_FAMILY_SUUNTO_EON:
rc = suunto_eon_parser_create (&parser, context, 0);
break;
case DC_FAMILY_SUUNTO_VYPER:
if (model == 0x01)
rc = suunto_eon_parser_create (&parser, context, 1);
else
rc = suunto_vyper_parser_create (&parser, context);
break;
case DC_FAMILY_SUUNTO_VYPER2:
case DC_FAMILY_SUUNTO_D9:
rc = suunto_d9_parser_create (&parser, context, model);
break;
case DC_FAMILY_SUUNTO_EONSTEEL:
rc = suunto_eonsteel_parser_create(&parser, context, model);
break;
case DC_FAMILY_UWATEC_ALADIN:
case DC_FAMILY_UWATEC_MEMOMOUSE:
rc = uwatec_memomouse_parser_create (&parser, context, devtime, systime);
break;
case DC_FAMILY_UWATEC_SMART:
case DC_FAMILY_UWATEC_MERIDIAN:
rc = uwatec_smart_parser_create (&parser, context, model, devtime, systime);
break;
case DC_FAMILY_REEFNET_SENSUS:
rc = reefnet_sensus_parser_create (&parser, context, devtime, systime);
break;
case DC_FAMILY_REEFNET_SENSUSPRO:
rc = reefnet_sensuspro_parser_create (&parser, context, devtime, systime);
break;
case DC_FAMILY_REEFNET_SENSUSULTRA:
rc = reefnet_sensusultra_parser_create (&parser, context, devtime, systime);
break;
case DC_FAMILY_OCEANIC_VTPRO:
rc = oceanic_vtpro_parser_create (&parser, context);
break;
case DC_FAMILY_OCEANIC_VEO250:
rc = oceanic_veo250_parser_create (&parser, context, model);
break;
case DC_FAMILY_OCEANIC_ATOM2:
if (model == REACTPROWHITE)
rc = oceanic_veo250_parser_create (&parser, context, model);
else
rc = oceanic_atom2_parser_create (&parser, context, model);
break;
case DC_FAMILY_MARES_NEMO:
case DC_FAMILY_MARES_PUCK:
rc = mares_nemo_parser_create (&parser, context, model);
break;
case DC_FAMILY_MARES_DARWIN:
rc = mares_darwin_parser_create (&parser, context, model);
break;
case DC_FAMILY_MARES_ICONHD:
rc = mares_iconhd_parser_create (&parser, context, model);
break;
case DC_FAMILY_HW_OSTC:
rc = hw_ostc_parser_create (&parser, context, 0);
break;
case DC_FAMILY_HW_FROG:
case DC_FAMILY_HW_OSTC3:
rc = hw_ostc_parser_create (&parser, context, 1);
break;
case DC_FAMILY_CRESSI_EDY:
case DC_FAMILY_ZEAGLE_N2ITION3:
rc = cressi_edy_parser_create (&parser, context, model);
break;
case DC_FAMILY_CRESSI_LEONARDO:
rc = cressi_leonardo_parser_create (&parser, context);
break;
case DC_FAMILY_ATOMICS_COBALT:
rc = atomics_cobalt_parser_create (&parser, context);
break;
case DC_FAMILY_SHEARWATER_PREDATOR:
rc = shearwater_predator_parser_create (&parser, context);
break;
case DC_FAMILY_SHEARWATER_PETREL:
rc = shearwater_petrel_parser_create (&parser, context);
break;
case DC_FAMILY_DIVERITE_NITEKQ:
rc = diverite_nitekq_parser_create (&parser, context);
break;
case DC_FAMILY_CITIZEN_AQUALAND:
rc = citizen_aqualand_parser_create (&parser, context);
break;
case DC_FAMILY_DIVESYSTEM_IDIVE:
rc = divesystem_idive_parser_create2 (&parser, context, model);
break;
default:
rc = DC_STATUS_INVALIDARGS;
break;
}
if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error creating the parser.");
goto cleanup;
}
// Register the data.
message ("Registering the data.\n");
rc = dc_parser_set_data (parser, data, size);
if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error registering the data.");
goto cleanup;
}
// Parse the dive data.
message ("Parsing the dive data.\n");
rc = dctool_output_write (output, parser, data, size, NULL, 0);
if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error parsing the dive data.");
goto cleanup;
}
cleanup:
dc_parser_destroy (parser);
return rc;
}
static int
dctool_parse_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t *descriptor)
{
// Default values.
int exitcode = EXIT_SUCCESS;
dc_status_t status = DC_STATUS_SUCCESS;
dc_buffer_t *buffer = NULL;
dctool_output_t *output = NULL;
// Default option values.
unsigned int help = 0;
const char *filename = NULL;
unsigned int devtime = 0;
dc_ticks_t systime = 0;
// Parse the command-line options.
int opt = 0;
const char *optstring = "ho:d:s:";
#ifdef HAVE_GETOPT_LONG
struct option options[] = {
{"help", no_argument, 0, 'h'},
{"output", required_argument, 0, 'o'},
{"devtime", required_argument, 0, 'd'},
{"systime", required_argument, 0, 's'},
{0, 0, 0, 0 }
};
while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) {
#else
while ((opt = getopt (argc, argv, optstring)) != -1) {
#endif
switch (opt) {
case 'h':
help = 1;
break;
case 'o':
filename = optarg;
break;
case 'd':
devtime = strtoul (optarg, NULL, 0);
break;
case 's':
systime = strtoll (optarg, NULL, 0);
break;
default:
return EXIT_FAILURE;
}
}
argc -= optind;
argv += optind;
// Show help message.
if (help) {
dctool_command_showhelp (&dctool_parse);
return EXIT_SUCCESS;
}
// Create the output.
output = dctool_xml_output_new (filename);
if (output == NULL) {
message ("Failed to create the output.\n");
exitcode = EXIT_FAILURE;
goto cleanup;
}
for (unsigned int i = 0; i < argc; ++i) {
// Read the input file.
buffer = dctool_file_read (argv[i]);
if (buffer == NULL) {
message ("Failed to open the input file.\n");
exitcode = EXIT_FAILURE;
goto cleanup;
}
// Parse the dive.
status = parse (buffer, context, descriptor, devtime, systime, output);
if (status != DC_STATUS_SUCCESS) {
message ("ERROR: %s\n", dctool_errmsg (status));
exitcode = EXIT_FAILURE;
goto cleanup;
}
// Cleanup.
dc_buffer_free (buffer);
buffer = NULL;
}
cleanup:
dc_buffer_free (buffer);
dctool_output_free (output);
return exitcode;
}
const dctool_command_t dctool_parse = {
dctool_parse_run,
DCTOOL_CONFIG_DESCRIPTOR,
"parse",
"Parse previously downloaded dives",
"Usage:\n"
" dctool parse [options] <filename>\n"
"\n"
"Options:\n"
#ifdef HAVE_GETOPT_LONG
" -h, --help Show help message\n"
" -o, --output <filename> Output filename\n"
" -d, --devtime <timestamp> Device time\n"
" -s, --systime <timestamp> System time\n"
#else
" -h Show help message\n"
" -o <filename> Output filename\n"
" -d <devtime> Device time\n"
" -s <systime> System time\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;
}

58
examples/output-private.h Normal file
View File

@ -0,0 +1,58 @@
/*
* libdivecomputer
*
* Copyright (C) 2016 Jef Driesen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef DCTOOL_OUTPUT_PRIVATE_H
#define DCTOOL_OUTPUT_PRIVATE_H
#include <libdivecomputer/common.h>
#include <libdivecomputer/parser.h>
#include "output.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct dctool_output_vtable_t dctool_output_vtable_t;
struct dctool_output_t {
const dctool_output_vtable_t *vtable;
unsigned int number;
};
struct dctool_output_vtable_t {
size_t size;
dc_status_t (*write) (dctool_output_t *output, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize);
dc_status_t (*free) (dctool_output_t *output);
};
dctool_output_t *
dctool_output_allocate (const dctool_output_vtable_t *vtable);
void
dctool_output_deallocate (dctool_output_t *output);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* DCTOOL_OUTPUT_PRIVATE_H */

79
examples/output.c Normal file
View File

@ -0,0 +1,79 @@
/*
* libdivecomputer
*
* Copyright (C) 2016 Jef Driesen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <stdlib.h>
#include <assert.h>
#include "output-private.h"
dctool_output_t *
dctool_output_allocate (const dctool_output_vtable_t *vtable)
{
dctool_output_t *output = NULL;
assert(vtable != NULL);
assert(vtable->size >= sizeof(dctool_output_t));
// Allocate memory.
output = (dctool_output_t *) malloc (vtable->size);
if (output == NULL) {
return output;
}
output->vtable = vtable;
output->number = 0;
return output;
}
void
dctool_output_deallocate (dctool_output_t *output)
{
free (output);
}
dc_status_t
dctool_output_write (dctool_output_t *output, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize)
{
if (output == NULL || output->vtable->write == NULL)
return DC_STATUS_SUCCESS;
output->number++;
return output->vtable->write (output, parser, data, size, fingerprint, fsize);
}
dc_status_t
dctool_output_free (dctool_output_t *output)
{
dc_status_t status = DC_STATUS_SUCCESS;
if (output == NULL)
return DC_STATUS_SUCCESS;
if (output->vtable->free) {
status = output->vtable->free (output);
}
dctool_output_deallocate (output);
return status;
}

49
examples/output.h Normal file
View File

@ -0,0 +1,49 @@
/*
* libdivecomputer
*
* Copyright (C) 2016 Jef Driesen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef DCTOOL_OUTPUT_H
#define DCTOOL_OUTPUT_H
#include <libdivecomputer/common.h>
#include <libdivecomputer/parser.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct dctool_output_t dctool_output_t;
dctool_output_t *
dctool_xml_output_new (const char *filename);
dctool_output_t *
dctool_raw_output_new (const char *template);
dc_status_t
dctool_output_write (dctool_output_t *output, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize);
dc_status_t
dctool_output_free (dctool_output_t *output);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* DCTOOL_OUTPUT_H */

219
examples/output_raw.c Normal file
View File

@ -0,0 +1,219 @@
/*
* libdivecomputer
*
* Copyright (C) 2016 Jef Driesen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "output-private.h"
#include "utils.h"
static dc_status_t dctool_raw_output_write (dctool_output_t *output, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize);
static dc_status_t dctool_raw_output_free (dctool_output_t *output);
typedef struct dctool_raw_output_t {
dctool_output_t base;
char *template;
} dctool_raw_output_t;
static const dctool_output_vtable_t raw_vtable = {
sizeof(dctool_raw_output_t), /* size */
dctool_raw_output_write, /* write */
dctool_raw_output_free, /* free */
};
static int
mktemplate_fingerprint (char *buffer, size_t size, const unsigned char fingerprint[], size_t fsize)
{
const unsigned char ascii[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
if (size < 2 * fsize + 1)
return -1;
for (size_t i = 0; i < fsize; ++i) {
// Set the most-significant nibble.
unsigned char msn = (fingerprint[i] >> 4) & 0x0F;
buffer[i * 2 + 0] = ascii[msn];
// Set the least-significant nibble.
unsigned char lsn = fingerprint[i] & 0x0F;
buffer[i * 2 + 1] = ascii[lsn];
}
// Null-terminate the string.
buffer[fsize * 2] = 0;
return fsize * 2;
}
static int
mktemplate_datetime (char *buffer, size_t size, dc_parser_t *parser)
{
dc_status_t rc = DC_STATUS_SUCCESS;
dc_datetime_t datetime = {0};
int n = 0;
rc = dc_parser_get_datetime (parser, &datetime);
if (rc != DC_STATUS_SUCCESS)
return -1;
n = snprintf (buffer, size, "%04i%02i%02iT%02i%02i%02i",
datetime.year, datetime.month, datetime.day,
datetime.hour, datetime.minute, datetime.second);
if (n < 0 || n >= size)
return -1;
return n;
}
static int
mktemplate_number (char *buffer, size_t size, unsigned int number)
{
int n = 0;
n = snprintf (buffer, size, "%04u", number);
if (n < 0 || n >= size)
return -1;
return n;
}
static int
mktemplate (char *buffer, size_t size, const char *format, dc_parser_t *parser, const unsigned char fingerprint[], size_t fsize, unsigned int number)
{
const char *p = format;
size_t n = 0;
int len = 0;
char ch = 0;
while ((ch = *p++) != 0) {
if (ch != '%') {
if (n >= size)
return -1;
buffer[n] = ch;
n++;
continue;
}
ch = *p++;
switch (ch) {
case '%':
if (n >= size)
return -1;
buffer[n] = ch;
n++;
break;
case 't': // Timestamp
len = mktemplate_datetime (buffer + n, size - n, parser);
if (len < 0)
return -1;
n += len;
break;
case 'f': // Fingerprint
len = mktemplate_fingerprint (buffer + n, size - n, fingerprint, fsize);
if (len < 0)
return -1;
n += len;
break;
case 'n': // Number
len = mktemplate_number (buffer + n, size - n, number);
if (len < 0)
return -1;
n += len;
break;
default:
return -1;
}
}
// Null-terminate the string
if (n >= size)
return -1;
buffer[n] = 0;
return n;
}
dctool_output_t *
dctool_raw_output_new (const char *template)
{
dctool_raw_output_t *output = NULL;
if (template == NULL)
goto error_exit;
// Allocate memory.
output = (dctool_raw_output_t *) dctool_output_allocate (&raw_vtable);
if (output == NULL) {
goto error_exit;
}
output->template = strdup(template);
if (output->template == NULL) {
goto error_free;
}
return (dctool_output_t *) output;
error_free:
dctool_output_deallocate ((dctool_output_t *) output);
error_exit:
return NULL;
}
static dc_status_t
dctool_raw_output_write (dctool_output_t *abstract, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize)
{
dctool_raw_output_t *output = (dctool_raw_output_t *) abstract;
// Generate the filename.
char name[1024] = {0};
int ret = mktemplate (name, sizeof(name), output->template, parser, fingerprint, fsize, abstract->number);
if (ret < 0) {
ERROR("Failed to generate filename from template.");
return DC_STATUS_SUCCESS;
}
// Open the output file.
FILE *fp = fopen (name, "wb");
if (fp == NULL) {
ERROR("Failed to open the output file.");
return DC_STATUS_SUCCESS;
}
// Write the data.
fwrite (data, sizeof (unsigned char), size, fp);
fclose (fp);
return DC_STATUS_SUCCESS;
}
static dc_status_t
dctool_raw_output_free (dctool_output_t *abstract)
{
dctool_raw_output_t *output = (dctool_raw_output_t *) abstract;
free (output->template);
return DC_STATUS_SUCCESS;
}

365
examples/output_xml.c Normal file
View File

@ -0,0 +1,365 @@
/*
* libdivecomputer
*
* Copyright (C) 2016 Jef Driesen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "output-private.h"
#include "utils.h"
static dc_status_t dctool_xml_output_write (dctool_output_t *output, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize);
static dc_status_t dctool_xml_output_free (dctool_output_t *output);
typedef struct dctool_xml_output_t {
dctool_output_t base;
FILE *ostream;
} dctool_xml_output_t;
static const dctool_output_vtable_t xml_vtable = {
sizeof(dctool_xml_output_t), /* size */
dctool_xml_output_write, /* write */
dctool_xml_output_free, /* free */
};
typedef struct sample_data_t {
FILE *ostream;
unsigned int nsamples;
} sample_data_t;
static void
sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata)
{
static const char *events[] = {
"none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter",
"violation", "bookmark", "surface", "safety stop", "gaschange",
"safety stop (voluntary)", "safety stop (mandatory)", "deepstop",
"ceiling (safety stop)", "floor", "divetime", "maxdepth",
"OLF", "PO2", "airtime", "rgbm", "heading", "tissue level warning",
"gaschange2"};
static const char *decostop[] = {
"ndl", "safety", "deco", "deep"};
sample_data_t *sampledata = (sample_data_t *) userdata;
switch (type) {
case DC_SAMPLE_TIME:
if (sampledata->nsamples++)
fprintf (sampledata->ostream, "</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;
}
}
dctool_output_t *
dctool_xml_output_new (const char *filename)
{
dctool_xml_output_t *output = NULL;
if (filename == NULL)
goto error_exit;
// Allocate memory.
output = (dctool_xml_output_t *) dctool_output_allocate (&xml_vtable);
if (output == NULL) {
goto error_exit;
}
// Open the output file.
output->ostream = fopen (filename, "w");
if (output->ostream == NULL) {
goto error_free;
}
fprintf (output->ostream, "<device>\n");
return (dctool_output_t *) output;
error_free:
dctool_output_deallocate ((dctool_output_t *) output);
error_exit:
return NULL;
}
static dc_status_t
dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const unsigned char data[], unsigned int size, const unsigned char fingerprint[], unsigned int fsize)
{
dctool_xml_output_t *output = (dctool_xml_output_t *) abstract;
dc_status_t status = DC_STATUS_SUCCESS;
fprintf (output->ostream, "<dive>\n<number>%u</number>\n<size>%u</size>\n", abstract->number, size);
if (fingerprint) {
fprintf (output->ostream, "<fingerprint>");
for (unsigned int i = 0; i < fsize; ++i)
fprintf (output->ostream, "%02X", fingerprint[i]);
fprintf (output->ostream, "</fingerprint>\n");
}
// Parse the datetime.
message ("Parsing the datetime.\n");
dc_datetime_t dt = {0};
status = dc_parser_get_datetime (parser, &dt);
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
ERROR ("Error parsing the datetime.");
goto cleanup;
}
fprintf (output->ostream, "<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;
status = dc_parser_get_field (parser, DC_FIELD_DIVETIME, 0, &divetime);
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
ERROR ("Error parsing the divetime.");
goto cleanup;
}
fprintf (output->ostream, "<divetime>%02u:%02u</divetime>\n",
divetime / 60, divetime % 60);
// Parse the maxdepth.
message ("Parsing the maxdepth.\n");
double maxdepth = 0.0;
status = dc_parser_get_field (parser, DC_FIELD_MAXDEPTH, 0, &maxdepth);
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
ERROR ("Error parsing the maxdepth.");
goto cleanup;
}
fprintf (output->ostream, "<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;
status = dc_parser_get_field (parser, fields[i], 0, &temperature);
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
ERROR ("Error parsing the temperature.");
goto cleanup;
}
if (status != DC_STATUS_UNSUPPORTED) {
fprintf (output->ostream, "<temperature type=\"%s\">%.1f</temperature>\n",
names[i], temperature);
}
}
// Parse the gas mixes.
message ("Parsing the gas mixes.\n");
unsigned int ngases = 0;
status = dc_parser_get_field (parser, DC_FIELD_GASMIX_COUNT, 0, &ngases);
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
ERROR ("Error parsing the gas mix count.");
goto cleanup;
}
for (unsigned int i = 0; i < ngases; ++i) {
dc_gasmix_t gasmix = {0};
status = dc_parser_get_field (parser, DC_FIELD_GASMIX, i, &gasmix);
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
ERROR ("Error parsing the gas mix.");
goto cleanup;
}
fprintf (output->ostream,
"<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;
status = dc_parser_get_field (parser, DC_FIELD_TANK_COUNT, 0, &ntanks);
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
ERROR ("Error parsing the tank count.");
goto cleanup;
}
for (unsigned int i = 0; i < ntanks; ++i) {
const char *names[] = {"none", "metric", "imperial"};
dc_tank_t tank = {0};
status = dc_parser_get_field (parser, DC_FIELD_TANK, i, &tank);
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
ERROR ("Error parsing the tank.");
goto cleanup;
}
fprintf (output->ostream, "<tank>\n");
if (tank.gasmix != DC_GASMIX_UNKNOWN) {
fprintf (output->ostream,
" <gasmix>%u</gasmix>\n",
tank.gasmix);
}
if (tank.type != DC_TANKVOLUME_NONE) {
fprintf (output->ostream,
" <type>%s</type>\n"
" <volume>%.1f</volume>\n"
" <workpressure>%.2f</workpressure>\n",
names[tank.type], tank.volume, tank.workpressure);
}
fprintf (output->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;
status = dc_parser_get_field (parser, DC_FIELD_DIVEMODE, 0, &divemode);
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
ERROR ("Error parsing the dive mode.");
goto cleanup;
}
if (status != DC_STATUS_UNSUPPORTED) {
const char *names[] = {"freedive", "gauge", "oc", "cc"};
fprintf (output->ostream, "<divemode>%s</divemode>\n",
names[divemode]);
}
// Parse the salinity.
message ("Parsing the salinity.\n");
dc_salinity_t salinity = {DC_WATER_FRESH, 0.0};
status = dc_parser_get_field (parser, DC_FIELD_SALINITY, 0, &salinity);
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
ERROR ("Error parsing the salinity.");
goto cleanup;
}
if (status != DC_STATUS_UNSUPPORTED) {
fprintf (output->ostream, "<salinity type=\"%u\">%.1f</salinity>\n",
salinity.type, salinity.density);
}
// Parse the atmospheric pressure.
message ("Parsing the atmospheric pressure.\n");
double atmospheric = 0.0;
status = dc_parser_get_field (parser, DC_FIELD_ATMOSPHERIC, 0, &atmospheric);
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
ERROR ("Error parsing the atmospheric pressure.");
goto cleanup;
}
if (status != DC_STATUS_UNSUPPORTED) {
fprintf (output->ostream, "<atmospheric>%.5f</atmospheric>\n",
atmospheric);
}
// Initialize the sample data.
sample_data_t sampledata = {0};
sampledata.nsamples = 0;
sampledata.ostream = output->ostream;
// Parse the sample data.
message ("Parsing the sample data.\n");
status = dc_parser_samples_foreach (parser, sample_cb, &sampledata);
if (status != DC_STATUS_SUCCESS) {
ERROR ("Error parsing the sample data.");
goto cleanup;
}
if (sampledata.nsamples)
fprintf (output->ostream, "</sample>\n");
fprintf (output->ostream, "</dive>\n");
cleanup:
return status;
}
static dc_status_t
dctool_xml_output_free (dctool_output_t *abstract)
{
dctool_xml_output_t *output = (dctool_xml_output_t *) abstract;
fprintf (output->ostream, "</device>\n");
fclose (output->ostream);
return DC_STATUS_SUCCESS;
}

View File

@ -1,980 +0,0 @@
/*
* libdivecomputer
*
* Copyright (C) 2009 Jef Driesen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <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_GASCHANGE2) {
fprintf (sampledata->fp, " <gaschange o2=\"%u\" he=\"%u\" />\n",
value.event.value & 0xFFFF, (value.event.value >> 16) & 0xFFFF);
} else if (value.event.type == SAMPLE_EVENT_GASCHANGE) {
fprintf (sampledata->fp, " <gaschange o2=\"%u\" />\n",
value.event.value);
} 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;
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);

View File

@ -33,9 +33,15 @@ extern "C" {
dc_status_t
divesystem_idive_device_open (dc_device_t **device, dc_context_t *context, const char *name);
dc_status_t
divesystem_idive_device_open2 (dc_device_t **device, dc_context_t *context, const char *name, unsigned int model);
dc_status_t
divesystem_idive_parser_create (dc_parser_t **parser, dc_context_t *context);
dc_status_t
divesystem_idive_parser_create2 (dc_parser_t **parser, dc_context_t *context, unsigned int model);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -43,7 +43,8 @@ typedef enum dc_sample_type_t {
DC_SAMPLE_SETPOINT,
DC_SAMPLE_PPO2,
DC_SAMPLE_CNS,
DC_SAMPLE_DECO
DC_SAMPLE_DECO,
DC_SAMPLE_GASMIX
} dc_sample_type_t;
typedef enum dc_field_type_t {
@ -78,7 +79,7 @@ typedef enum parser_sample_event_t {
SAMPLE_EVENT_BOOKMARK,
SAMPLE_EVENT_SURFACE,
SAMPLE_EVENT_SAFETYSTOP,
SAMPLE_EVENT_GASCHANGE, /* The event value contains the O2 percentage. */
SAMPLE_EVENT_GASCHANGE, /* Deprecated: replaced by DC_SAMPLE_GASMIX. */
SAMPLE_EVENT_SAFETYSTOP_VOLUNTARY,
SAMPLE_EVENT_SAFETYSTOP_MANDATORY,
SAMPLE_EVENT_DEEPSTOP,
@ -92,9 +93,7 @@ typedef enum parser_sample_event_t {
SAMPLE_EVENT_RGBM,
SAMPLE_EVENT_HEADING,
SAMPLE_EVENT_TISSUELEVEL,
SAMPLE_EVENT_GASCHANGE2, /* The event value contains the O2 and He
percentages, packed as two 16bit integers in
respectively the low and high part. */
SAMPLE_EVENT_GASCHANGE2, /* Deprecated: replaced by DC_SAMPLE_GASMIX. */
} parser_sample_event_t;
/* For backwards compatibility */
@ -220,6 +219,7 @@ typedef union dc_sample_value_t {
unsigned int time;
double depth;
} deco;
unsigned int gasmix; /* Gas mix index */
} dc_sample_value_t;
typedef struct dc_parser_t dc_parser_t;

View File

@ -210,6 +210,10 @@
RelativePath="..\src\citizen_aqualand_parser.c"
>
</File>
<File
RelativePath="..\src\common.c"
>
</File>
<File
RelativePath="..\src\context.c"
>
@ -520,6 +524,10 @@
RelativePath="..\include\libdivecomputer\citizen_aqualand.h"
>
</File>
<File
RelativePath="..\src\common-private.h"
>
</File>
<File
RelativePath="..\src\context-private.h"
>

View File

@ -1,5 +1,5 @@
AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
AM_CFLAGS = $(LIBUSB_CFLAGS) $(HIDAPI_CFLAGS)
AM_CFLAGS = $(LIBUSB_CFLAGS) $(HIDAPI_CFLAGS) -DENABLE_DEPRECATED
lib_LTLIBRARIES = libdivecomputer.la
@ -17,6 +17,7 @@ libdivecomputer_la_SOURCES = \
version.c \
descriptor.c \
iterator-private.h iterator.c \
common-private.h common.c \
context-private.h context.c \
device-private.h device.c \
parser-private.h parser.c \

View File

@ -69,6 +69,7 @@ static dc_status_t atomics_cobalt_device_foreach (dc_device_t *abstract, dc_dive
static dc_status_t atomics_cobalt_device_close (dc_device_t *abstract);
static const dc_device_vtable_t atomics_cobalt_device_vtable = {
sizeof(atomics_cobalt_device_t),
DC_FAMILY_ATOMICS_COBALT,
atomics_cobalt_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -82,20 +83,22 @@ static const dc_device_vtable_t atomics_cobalt_device_vtable = {
dc_status_t
atomics_cobalt_device_open (dc_device_t **out, dc_context_t *context)
{
#ifdef HAVE_LIBUSB
dc_status_t status = DC_STATUS_SUCCESS;
atomics_cobalt_device_t *device = NULL;
#endif
if (out == NULL)
return DC_STATUS_INVALIDARGS;
#ifdef HAVE_LIBUSB
// Allocate memory.
atomics_cobalt_device_t *device = (atomics_cobalt_device_t *) malloc (sizeof (atomics_cobalt_device_t));
device = (atomics_cobalt_device_t *) dc_device_allocate (context, &atomics_cobalt_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &atomics_cobalt_device_vtable);
// Set the default values.
device->context = NULL;
device->handle = NULL;
@ -105,39 +108,41 @@ atomics_cobalt_device_open (dc_device_t **out, dc_context_t *context)
int rc = libusb_init (&device->context);
if (rc < 0) {
ERROR (context, "Failed to initialize usb support.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
device->handle = libusb_open_device_with_vid_pid (device->context, VID, PID);
if (device->handle == NULL) {
ERROR (context, "Failed to open the usb device.");
libusb_exit (device->context);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_usb_exit;
}
rc = libusb_claim_interface (device->handle, 0);
if (rc < 0) {
ERROR (context, "Failed to claim the usb interface.");
libusb_close (device->handle);
libusb_exit (device->context);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_usb_close;
}
dc_status_t status = atomics_cobalt_device_version ((dc_device_t *) device, device->version, sizeof (device->version));
status = atomics_cobalt_device_version ((dc_device_t *) device, device->version, sizeof (device->version));
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to identify the dive computer.");
libusb_close (device->handle);
libusb_exit (device->context);
free (device);
return status;
goto error_usb_close;
}
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_usb_close:
libusb_close (device->handle);
error_usb_exit:
libusb_exit (device->context);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
#else
return DC_STATUS_UNSUPPORTED;
#endif
@ -155,9 +160,6 @@ atomics_cobalt_device_close (dc_device_t *abstract)
libusb_exit (device->context);
#endif
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
}

View File

@ -54,34 +54,33 @@ static dc_status_t atomics_cobalt_parser_set_data (dc_parser_t *abstract, const
static dc_status_t atomics_cobalt_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t atomics_cobalt_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t atomics_cobalt_parser_vtable = {
sizeof(atomics_cobalt_parser_t),
DC_FAMILY_ATOMICS_COBALT,
atomics_cobalt_parser_set_data, /* set_data */
atomics_cobalt_parser_get_datetime, /* datetime */
atomics_cobalt_parser_get_field, /* fields */
atomics_cobalt_parser_samples_foreach, /* samples_foreach */
atomics_cobalt_parser_destroy /* destroy */
NULL /* destroy */
};
dc_status_t
atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context)
{
atomics_cobalt_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
atomics_cobalt_parser_t *parser = (atomics_cobalt_parser_t *) malloc (sizeof (atomics_cobalt_parser_t));
parser = (atomics_cobalt_parser_t *) dc_parser_allocate (context, &atomics_cobalt_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &atomics_cobalt_parser_vtable);
// Set the default values.
parser->atmospheric = 0.0;
parser->hydrostatic = 1025.0 * GRAVITY;
@ -92,16 +91,6 @@ atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context)
}
static dc_status_t
atomics_cobalt_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
atomics_cobalt_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
@ -341,6 +330,9 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
ERROR (abstract->context, "Invalid gas mix index.");
return DC_STATUS_DATAFORMAT;
}
sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
unsigned int o2 = data[SZ_HEADER + SZ_GASMIX * idx + 4];
unsigned int he = data[SZ_HEADER + SZ_GASMIX * idx + 5];
sample.event.type = SAMPLE_EVENT_GASCHANGE2;
@ -348,6 +340,7 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
sample.event.flags = 0;
sample.event.value = o2 | (he << 16);
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
#endif
gasmix_previous = gasmix;
}

View File

@ -50,6 +50,7 @@ static dc_status_t citizen_aqualand_device_foreach (dc_device_t *abstract, dc_di
static dc_status_t citizen_aqualand_device_close (dc_device_t *abstract);
static const dc_device_vtable_t citizen_aqualand_device_vtable = {
sizeof(citizen_aqualand_device_t),
DC_FAMILY_CITIZEN_AQUALAND,
citizen_aqualand_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -63,19 +64,19 @@ static const dc_device_vtable_t citizen_aqualand_device_vtable = {
dc_status_t
citizen_aqualand_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
citizen_aqualand_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
citizen_aqualand_device_t *device = (citizen_aqualand_device_t *) malloc (sizeof (citizen_aqualand_device_t));
device = (citizen_aqualand_device_t *) dc_device_allocate (context, &citizen_aqualand_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &citizen_aqualand_device_vtable);
// Set the default values.
device->port = NULL;
memset (device->fingerprint, 0, sizeof (device->fingerprint));
@ -84,25 +85,23 @@ citizen_aqualand_device_open (dc_device_t **out, dc_context_t *context, const ch
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (4800 8N1).
rc = serial_configure (device->port, 4800, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (1000ms).
if (serial_set_timeout (device->port, 1000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -112,24 +111,27 @@ citizen_aqualand_device_open (dc_device_t **out, dc_context_t *context, const ch
*out = (dc_device_t *) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
citizen_aqualand_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
citizen_aqualand_device_t *device = (citizen_aqualand_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -40,50 +40,39 @@ static dc_status_t citizen_aqualand_parser_set_data (dc_parser_t *abstract, cons
static dc_status_t citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t citizen_aqualand_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t citizen_aqualand_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t citizen_aqualand_parser_vtable = {
sizeof(citizen_aqualand_parser_t),
DC_FAMILY_CITIZEN_AQUALAND,
citizen_aqualand_parser_set_data, /* set_data */
citizen_aqualand_parser_get_datetime, /* datetime */
citizen_aqualand_parser_get_field, /* fields */
citizen_aqualand_parser_samples_foreach, /* samples_foreach */
citizen_aqualand_parser_destroy /* destroy */
NULL /* destroy */
};
dc_status_t
citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context)
{
citizen_aqualand_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
citizen_aqualand_parser_t *parser = (citizen_aqualand_parser_t *) malloc (sizeof (citizen_aqualand_parser_t));
parser = (citizen_aqualand_parser_t *) dc_parser_allocate (context, &citizen_aqualand_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &citizen_aqualand_parser_vtable);
*out = (dc_parser_t*) parser;
return DC_STATUS_SUCCESS;
}
static dc_status_t
citizen_aqualand_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
citizen_aqualand_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{

37
src/common-private.h Normal file
View File

@ -0,0 +1,37 @@
/*
* libdivecomputer
*
* Copyright (C) 2015 Jef Driesen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef COMMON_PRIVATE_H
#define COMMON_PRIVATE_H
#include <libdivecomputer/common.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
void
dc_status_set_error (dc_status_t *status, dc_status_t error);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* COMMON_PRIVATE_H */

34
src/common.c Normal file
View File

@ -0,0 +1,34 @@
/*
* libdivecomputer
*
* Copyright (C) 2015 Jef Driesen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <stdlib.h>
#include <assert.h>
#include "common-private.h"
void
dc_status_set_error (dc_status_t *status, dc_status_t error)
{
assert (status != NULL);
if (*status == DC_STATUS_SUCCESS)
*status = error;
}

View File

@ -73,6 +73,7 @@ static dc_status_t cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_cal
static dc_status_t cressi_edy_device_close (dc_device_t *abstract);
static const dc_device_vtable_t cressi_edy_device_vtable = {
sizeof(cressi_edy_device_t),
DC_FAMILY_CRESSI_EDY,
cressi_edy_device_set_fingerprint, /* set_fingerprint */
cressi_edy_device_read, /* read */
@ -236,19 +237,19 @@ cressi_edy_quit (cressi_edy_device_t *device)
dc_status_t
cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
cressi_edy_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
cressi_edy_device_t *device = (cressi_edy_device_t *) malloc (sizeof (cressi_edy_device_t));
device = (cressi_edy_device_t *) dc_device_allocate (context, &cressi_edy_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &cressi_edy_device_vtable);
// Set the default values.
device->port = NULL;
device->layout = NULL;
@ -259,34 +260,31 @@ cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *na
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (1200 8N1).
rc = serial_configure (device->port, 1200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->port, 1000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the DTR and clear the RTS line.
if (serial_set_dtr (device->port, 1) == -1 ||
serial_set_rts (device->port, 0) == -1) {
ERROR (context, "Failed to set the DTR/RTS line.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -308,9 +306,8 @@ cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *na
rc = serial_configure (device->port, 4800, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -320,12 +317,19 @@ cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *na
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
cressi_edy_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
cressi_edy_device_t *device = (cressi_edy_device_t*) abstract;
// Send the quit command.
@ -333,14 +337,10 @@ cressi_edy_device_close (dc_device_t *abstract)
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -43,15 +43,15 @@ static dc_status_t cressi_edy_parser_set_data (dc_parser_t *abstract, const unsi
static dc_status_t cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t cressi_edy_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t cressi_edy_parser_vtable = {
sizeof(cressi_edy_parser_t),
DC_FAMILY_CRESSI_EDY,
cressi_edy_parser_set_data, /* set_data */
cressi_edy_parser_get_datetime, /* datetime */
cressi_edy_parser_get_field, /* fields */
cressi_edy_parser_samples_foreach, /* samples_foreach */
cressi_edy_parser_destroy /* destroy */
NULL /* destroy */
};
@ -73,19 +73,18 @@ cressi_edy_parser_count_gasmixes (const unsigned char *data)
dc_status_t
cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{
cressi_edy_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
cressi_edy_parser_t *parser = (cressi_edy_parser_t *) malloc (sizeof (cressi_edy_parser_t));
parser = (cressi_edy_parser_t *) dc_parser_allocate (context, &cressi_edy_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &cressi_edy_parser_vtable);
// Set the default values.
parser->model = model;
@ -95,16 +94,6 @@ cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int
}
static dc_status_t
cressi_edy_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
cressi_edy_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
@ -227,11 +216,15 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
return DC_STATUS_DATAFORMAT;
}
if (idx != gasmix) {
sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
sample.event.type = SAMPLE_EVENT_GASCHANGE;
sample.event.time = 0;
sample.event.flags = 0;
sample.event.value = bcd2dec(data[0x17 - idx]);
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
#endif
gasmix = idx;
}
}

View File

@ -62,6 +62,7 @@ static dc_status_t cressi_leonardo_device_foreach (dc_device_t *abstract, dc_div
static dc_status_t cressi_leonardo_device_close (dc_device_t *abstract);
static const dc_device_vtable_t cressi_leonardo_device_vtable = {
sizeof(cressi_leonardo_device_t),
DC_FAMILY_CRESSI_LEONARDO,
cressi_leonardo_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -74,19 +75,19 @@ static const dc_device_vtable_t cressi_leonardo_device_vtable = {
dc_status_t
cressi_leonardo_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
cressi_leonardo_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
cressi_leonardo_device_t *device = (cressi_leonardo_device_t *) malloc (sizeof (cressi_leonardo_device_t));
device = (cressi_leonardo_device_t *) dc_device_allocate (context, &cressi_leonardo_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &cressi_leonardo_device_vtable);
// Set the default values.
device->port = NULL;
memset (device->fingerprint, 0, sizeof (device->fingerprint));
@ -95,34 +96,31 @@ cressi_leonardo_device_open (dc_device_t **out, dc_context_t *context, const cha
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (115200 8N1).
rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->port, 1000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Clear the DTR and set the RTS line.
if (serial_set_dtr (device->port, 0) == -1 ||
serial_set_rts (device->port, 1) == -1) {
ERROR (context, "Failed to set the DTR/RTS line.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
serial_sleep (device->port, 100);
@ -131,23 +129,26 @@ cressi_leonardo_device_open (dc_device_t **out, dc_context_t *context, const cha
*out = (dc_device_t *) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
cressi_leonardo_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
cressi_leonardo_device_t *device = (cressi_leonardo_device_t *) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}
static dc_status_t

View File

@ -41,50 +41,39 @@ static dc_status_t cressi_leonardo_parser_set_data (dc_parser_t *abstract, const
static dc_status_t cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t cressi_leonardo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t cressi_leonardo_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t cressi_leonardo_parser_vtable = {
sizeof(cressi_leonardo_parser_t),
DC_FAMILY_CRESSI_EDY,
cressi_leonardo_parser_set_data, /* set_data */
cressi_leonardo_parser_get_datetime, /* datetime */
cressi_leonardo_parser_get_field, /* fields */
cressi_leonardo_parser_samples_foreach, /* samples_foreach */
cressi_leonardo_parser_destroy /* destroy */
NULL /* destroy */
};
dc_status_t
cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context)
{
cressi_leonardo_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
cressi_leonardo_parser_t *parser = (cressi_leonardo_parser_t *) malloc (sizeof (cressi_leonardo_parser_t));
parser = (cressi_leonardo_parser_t *) dc_parser_allocate (context, &cressi_leonardo_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &cressi_leonardo_parser_vtable);
*out = (dc_parser_t*) parser;
return DC_STATUS_SUCCESS;
}
static dc_status_t
cressi_leonardo_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
cressi_leonardo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{

View File

@ -179,6 +179,7 @@ static const dc_descriptor_t g_descriptors[] = {
{"Aeris", "F11", DC_FAMILY_OCEANIC_ATOM2, 0x4549},
{"Oceanic", "OCi", DC_FAMILY_OCEANIC_ATOM2, 0x454B},
{"Aeris", "A300CS", DC_FAMILY_OCEANIC_ATOM2, 0x454C},
{"Oceanic", "F11", DC_FAMILY_OCEANIC_ATOM2, 0x4554},
{"Oceanic", "VTX", DC_FAMILY_OCEANIC_ATOM2, 0x4557},
/* Mares Nemo */
{"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0},
@ -254,6 +255,10 @@ static const dc_descriptor_t g_descriptors[] = {
{"DiveSystem", "iDive Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x09},
{"DiveSystem", "iDive X3M", DC_FAMILY_DIVESYSTEM_IDIVE, 0x0A},
{"DiveSystem", "iDive Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x0B},
{"DiveSystem", "iX3M Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x22},
{"DiveSystem", "iX3M Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x23},
{"DiveSystem", "iX3M Tec", DC_FAMILY_DIVESYSTEM_IDIVE, 0x24},
{"DiveSystem", "iX3M Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x25},
};
typedef struct dc_descriptor_iterator_t {

View File

@ -27,6 +27,8 @@
#include <libdivecomputer/context.h>
#include <libdivecomputer/device.h>
#include "common-private.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
@ -55,6 +57,8 @@ struct dc_device_t {
};
struct dc_device_vtable_t {
size_t size;
dc_family_t type;
dc_status_t (*set_fingerprint) (dc_device_t *device, const unsigned char data[], unsigned int size);
@ -73,8 +77,11 @@ struct dc_device_vtable_t {
int
dc_device_isinstance (dc_device_t *device, const dc_device_vtable_t *vtable);
dc_device_t *
dc_device_allocate (dc_context_t *context, const dc_device_vtable_t *vtable);
void
device_init (dc_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable);
dc_device_deallocate (dc_device_t *device);
void
device_event_emit (dc_device_t *device, dc_event_type_t event, const void *data);

View File

@ -41,10 +41,21 @@
#include "device-private.h"
#include "context-private.h"
void
device_init (dc_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable)
dc_device_t *
dc_device_allocate (dc_context_t *context, const dc_device_vtable_t *vtable)
{
dc_device_t *device = NULL;
assert(vtable != NULL);
assert(vtable->size >= sizeof(dc_device_t));
// Allocate memory.
device = (dc_device_t *) malloc (vtable->size);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return device;
}
device->vtable = vtable;
device->context = context;
@ -58,6 +69,14 @@ device_init (dc_device_t *device, dc_context_t *context, const dc_device_vtable_
memset (&device->devinfo, 0, sizeof (device->devinfo));
memset (&device->clock, 0, sizeof (device->clock));
return device;
}
void
dc_device_deallocate (dc_device_t *device)
{
free (device);
}
dc_status_t
@ -164,7 +183,7 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
rc = citizen_aqualand_device_open (&device, context, name);
break;
case DC_FAMILY_DIVESYSTEM_IDIVE:
rc = divesystem_idive_device_open (&device, context, name);
rc = divesystem_idive_device_open2 (&device, context, name, dc_descriptor_get_model (descriptor));
break;
default:
return DC_STATUS_INVALIDARGS;
@ -355,17 +374,22 @@ dc_device_foreach (dc_device_t *device, dc_dive_callback_t callback, void *userd
dc_status_t
dc_device_close (dc_device_t *device)
{
dc_status_t status = DC_STATUS_SUCCESS;
if (device == NULL)
return DC_STATUS_SUCCESS;
if (device->vtable->close == NULL)
return DC_STATUS_UNSUPPORTED;
// Disable the cancellation callback.
device->cancel_callback = NULL;
device->cancel_userdata = NULL;
return device->vtable->close (device);
if (device->vtable->close) {
status = device->vtable->close (device);
}
dc_device_deallocate (device);
return status;
}

View File

@ -68,6 +68,7 @@ static dc_status_t diverite_nitekq_device_foreach (dc_device_t *abstract, dc_div
static dc_status_t diverite_nitekq_device_close (dc_device_t *abstract);
static const dc_device_vtable_t diverite_nitekq_device_vtable = {
sizeof(diverite_nitekq_device_t),
DC_FAMILY_DIVERITE_NITEKQ,
diverite_nitekq_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -149,19 +150,19 @@ diverite_nitekq_handshake (diverite_nitekq_device_t *device)
dc_status_t
diverite_nitekq_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
diverite_nitekq_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
diverite_nitekq_device_t *device = (diverite_nitekq_device_t *) malloc (sizeof (diverite_nitekq_device_t));
device = (diverite_nitekq_device_t *) dc_device_allocate (context, &diverite_nitekq_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &diverite_nitekq_device_vtable);
// Set the default values.
device->port = NULL;
memset (device->fingerprint, 0, sizeof (device->fingerprint));
@ -170,25 +171,23 @@ diverite_nitekq_device_open (dc_device_t **out, dc_context_t *context, const cha
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (1000ms).
if (serial_set_timeout (device->port, 1000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -196,24 +195,28 @@ diverite_nitekq_device_open (dc_device_t **out, dc_context_t *context, const cha
serial_flush (device->port, SERIAL_QUEUE_BOTH);
// Perform the handshaking.
dc_status_t status = diverite_nitekq_handshake (device);
status = diverite_nitekq_handshake (device);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to handshake.");
serial_close (device->port);
free (device);
return status;
goto error_close;
}
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
diverite_nitekq_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
diverite_nitekq_device_t *device = (diverite_nitekq_device_t*) abstract;
// Disconnect.
@ -221,14 +224,10 @@ diverite_nitekq_device_close (dc_device_t *abstract)
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -52,34 +52,33 @@ static dc_status_t diverite_nitekq_parser_set_data (dc_parser_t *abstract, const
static dc_status_t diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t diverite_nitekq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t diverite_nitekq_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t diverite_nitekq_parser_vtable = {
sizeof(diverite_nitekq_parser_t),
DC_FAMILY_DIVERITE_NITEKQ,
diverite_nitekq_parser_set_data, /* set_data */
diverite_nitekq_parser_get_datetime, /* datetime */
diverite_nitekq_parser_get_field, /* fields */
diverite_nitekq_parser_samples_foreach, /* samples_foreach */
diverite_nitekq_parser_destroy /* destroy */
NULL /* destroy */
};
dc_status_t
diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context)
{
diverite_nitekq_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
diverite_nitekq_parser_t *parser = (diverite_nitekq_parser_t *) malloc (sizeof (diverite_nitekq_parser_t));
parser = (diverite_nitekq_parser_t *) dc_parser_allocate (context, &diverite_nitekq_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &diverite_nitekq_parser_vtable);
// Set the default values.
parser->cached = 0;
parser->metric = 0;
@ -97,16 +96,6 @@ diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context)
}
static dc_status_t
diverite_nitekq_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
diverite_nitekq_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
@ -270,11 +259,15 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
// Gas change
if (gasmix != gasmix_previous) {
sample.gasmix = gasmix;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
sample.event.type = SAMPLE_EVENT_GASCHANGE2;
sample.event.time = 0;
sample.event.flags = 0;
sample.event.value = oxygen[gasmix] | (helium[gasmix] << 16);
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
#endif
gasmix_previous = gasmix;
}

View File

@ -37,6 +37,11 @@
rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \
)
#define IX3M_EASY 0x22
#define IX3M_DEEP 0x23
#define IX3M_TEC 0x24
#define IX3M_REB 0x25
#define MAXRETRIES 9
#define MAXPACKET 0xFF
@ -45,23 +50,26 @@
#define NAK 0x15
#define BUSY 0x60
#define CMD_ID 0x10
#define CMD_RANGE 0x98
#define CMD_HEADER 0xA0
#define CMD_SAMPLE 0xA8
#define SZ_ID 0x0A
#define SZ_RANGE 0x04
#define SZ_HEADER 0x32
#define SZ_SAMPLE 0x2A
#define NSTEPS 1000
#define STEP(i,n) (NSTEPS * (i) / (n))
typedef struct divesystem_idive_command_t {
unsigned char cmd;
unsigned int size;
} divesystem_idive_command_t;
typedef struct divesystem_idive_commands_t {
divesystem_idive_command_t id;
divesystem_idive_command_t range;
divesystem_idive_command_t header;
divesystem_idive_command_t sample;
} divesystem_idive_commands_t;
typedef struct divesystem_idive_device_t {
dc_device_t base;
serial_t *port;
unsigned char fingerprint[4];
unsigned int model;
} divesystem_idive_device_t;
static dc_status_t divesystem_idive_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
@ -69,6 +77,7 @@ static dc_status_t divesystem_idive_device_foreach (dc_device_t *abstract, dc_di
static dc_status_t divesystem_idive_device_close (dc_device_t *abstract);
static const dc_device_vtable_t divesystem_idive_device_vtable = {
sizeof(divesystem_idive_device_t),
DC_FAMILY_DIVESYSTEM_IDIVE,
divesystem_idive_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -78,50 +87,69 @@ static const dc_device_vtable_t divesystem_idive_device_vtable = {
divesystem_idive_device_close /* close */
};
static const divesystem_idive_commands_t idive = {
{0x10, 0x0A},
{0x98, 0x04},
{0xA0, 0x32},
{0xA8, 0x2A},
};
static const divesystem_idive_commands_t ix3m = {
{0x11, 0x1A},
{0x78, 0x04},
{0x79, 0x36},
{0x7A, 0x36},
};
dc_status_t
divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
return divesystem_idive_device_open2 (out, context, name, 0);
}
dc_status_t
divesystem_idive_device_open2 (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model)
{
dc_status_t status = DC_STATUS_SUCCESS;
divesystem_idive_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
divesystem_idive_device_t *device = (divesystem_idive_device_t *) malloc (sizeof (divesystem_idive_device_t));
device = (divesystem_idive_device_t *) dc_device_allocate (context, &divesystem_idive_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &divesystem_idive_device_vtable);
// Set the default values.
device->port = NULL;
memset (device->fingerprint, 0, sizeof (device->fingerprint));
device->model = model;
// Open the device.
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (115200 8N1).
rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (1000ms).
if (serial_set_timeout (device->port, 1000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -131,24 +159,27 @@ divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, const ch
*out = (dc_device_t *) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
divesystem_idive_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
divesystem_idive_device_t *device = (divesystem_idive_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}
@ -334,39 +365,43 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
{
dc_status_t rc = DC_STATUS_SUCCESS;
divesystem_idive_device_t *device = (divesystem_idive_device_t *) abstract;
unsigned char packet[MAXPACKET - 2];
const divesystem_idive_commands_t *commands = &idive;
if (device->model >= IX3M_EASY && device->model <= IX3M_REB) {
commands = &ix3m;
}
// Enable progress notifications.
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
unsigned char cmd_id[] = {CMD_ID, 0xED};
unsigned char id[SZ_ID];
rc = divesystem_idive_transfer (device, cmd_id, sizeof(cmd_id), id, sizeof(id));
unsigned char cmd_id[] = {commands->id.cmd, 0xED};
rc = divesystem_idive_transfer (device, cmd_id, sizeof(cmd_id), packet, commands->id.size);
if (rc != DC_STATUS_SUCCESS)
return rc;
// Emit a device info event.
dc_event_devinfo_t devinfo;
devinfo.model = array_uint16_le (id);
devinfo.model = array_uint16_le (packet);
devinfo.firmware = 0;
devinfo.serial = array_uint32_le (id + 6);
devinfo.serial = array_uint32_le (packet + 6);
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
// Emit a vendor event.
dc_event_vendor_t vendor;
vendor.data = id;
vendor.size = sizeof (id);
vendor.data = packet;
vendor.size = commands->id.size;
device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
unsigned char cmd_range[] = {CMD_RANGE, 0x8D};
unsigned char range[4];
rc = divesystem_idive_transfer (device, cmd_range, sizeof(cmd_range), range, sizeof(range));
unsigned char cmd_range[] = {commands->range.cmd, 0x8D};
rc = divesystem_idive_transfer (device, cmd_range, sizeof(cmd_range), packet, commands->range.size);
if (rc != DC_STATUS_SUCCESS)
return rc;
// Get the range of the available dive numbers.
unsigned int first = array_uint16_le (range + 0);
unsigned int last = array_uint16_le (range + 2);
unsigned int first = array_uint16_le (packet + 0);
unsigned int last = array_uint16_le (packet + 2);
if (first > last) {
ERROR(abstract->context, "Invalid dive numbers.");
return DC_STATUS_DATAFORMAT;
@ -386,34 +421,32 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
for (unsigned int i = 0; i < ndives; ++i) {
unsigned int number = last - i;
unsigned char cmd_header[] = {CMD_HEADER,
unsigned char cmd_header[] = {commands->header.cmd,
(number ) & 0xFF,
(number >> 8) & 0xFF};
unsigned char header[SZ_HEADER];
rc = divesystem_idive_transfer (device, cmd_header, sizeof(cmd_header), header, sizeof(header));
rc = divesystem_idive_transfer (device, cmd_header, sizeof(cmd_header), packet, commands->header.size);
if (rc != DC_STATUS_SUCCESS)
return rc;
if (memcmp(header + 7, device->fingerprint, sizeof(device->fingerprint)) == 0)
if (memcmp(packet + 7, device->fingerprint, sizeof(device->fingerprint)) == 0)
break;
unsigned int nsamples = array_uint16_le (header + 1);
unsigned int nsamples = array_uint16_le (packet + 1);
// Update and emit a progress event.
progress.current = i * NSTEPS + STEP(1, nsamples + 1);
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
dc_buffer_clear(buffer);
dc_buffer_reserve(buffer, SZ_HEADER + SZ_SAMPLE * nsamples);
dc_buffer_append(buffer, header, sizeof(header));
dc_buffer_reserve(buffer, commands->header.size + commands->sample.size * nsamples);
dc_buffer_append(buffer, packet, commands->header.size);
for (unsigned int j = 0; j < nsamples; ++j) {
unsigned int idx = j + 1;
unsigned char cmd_sample[] = {CMD_SAMPLE,
unsigned char cmd_sample[] = {commands->sample.cmd,
(idx ) & 0xFF,
(idx >> 8) & 0xFF};
unsigned char sample[SZ_SAMPLE];
rc = divesystem_idive_transfer (device, cmd_sample, sizeof(cmd_sample), sample, sizeof(sample));
rc = divesystem_idive_transfer (device, cmd_sample, sizeof(cmd_sample), packet, commands->sample.size);
if (rc != DC_STATUS_SUCCESS)
return rc;
@ -421,7 +454,7 @@ divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
progress.current = i * NSTEPS + STEP(j + 2, nsamples + 1);
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
dc_buffer_append(buffer, sample, sizeof(sample));
dc_buffer_append(buffer, packet, commands->sample.size);
}
unsigned char *data = dc_buffer_get_data(buffer);

View File

@ -29,8 +29,15 @@
#define ISINSTANCE(parser) dc_device_isinstance((parser), &divesystem_idive_parser_vtable)
#define SZ_HEADER 0x32
#define SZ_SAMPLE 0x2A
#define IX3M_EASY 0x22
#define IX3M_DEEP 0x23
#define IX3M_TEC 0x24
#define IX3M_REB 0x25
#define SZ_HEADER_IDIVE 0x32
#define SZ_SAMPLE_IDIVE 0x2A
#define SZ_HEADER_IX3M 0x36
#define SZ_SAMPLE_IX3M 0x36
#define NGASMIXES 8
@ -40,6 +47,8 @@ typedef struct divesystem_idive_parser_t divesystem_idive_parser_t;
struct divesystem_idive_parser_t {
dc_parser_t base;
unsigned int headersize;
unsigned int samplesize;
// Cached fields.
unsigned int cached;
unsigned int divetime;
@ -53,35 +62,48 @@ static dc_status_t divesystem_idive_parser_set_data (dc_parser_t *abstract, cons
static dc_status_t divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t divesystem_idive_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t divesystem_idive_parser_vtable = {
sizeof(divesystem_idive_parser_t),
DC_FAMILY_DIVESYSTEM_IDIVE,
divesystem_idive_parser_set_data, /* set_data */
divesystem_idive_parser_get_datetime, /* datetime */
divesystem_idive_parser_get_field, /* fields */
divesystem_idive_parser_samples_foreach, /* samples_foreach */
divesystem_idive_parser_destroy /* destroy */
NULL /* destroy */
};
dc_status_t
divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context)
{
return divesystem_idive_parser_create2 (out, context, 0);
}
dc_status_t
divesystem_idive_parser_create2 (dc_parser_t **out, dc_context_t *context, unsigned int model)
{
divesystem_idive_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
divesystem_idive_parser_t *parser = (divesystem_idive_parser_t *) malloc (sizeof (divesystem_idive_parser_t));
parser = (divesystem_idive_parser_t *) dc_parser_allocate (context, &divesystem_idive_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &divesystem_idive_parser_vtable);
// Set the default values.
if (model >= IX3M_EASY && model <= IX3M_REB) {
parser->headersize = SZ_HEADER_IX3M;
parser->samplesize = SZ_SAMPLE_IX3M;
} else {
parser->headersize = SZ_HEADER_IDIVE;
parser->samplesize = SZ_SAMPLE_IDIVE;
}
parser->cached = 0;
parser->divetime = 0;
parser->maxdepth = 0;
@ -97,16 +119,6 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context)
}
static dc_status_t
divesystem_idive_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
@ -129,7 +141,9 @@ divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *da
static dc_status_t
divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{
if (abstract->size < SZ_HEADER)
divesystem_idive_parser_t *parser = (divesystem_idive_parser_t *) abstract;
if (abstract->size < parser->headersize)
return DC_STATUS_DATAFORMAT;
dc_ticks_t ticks = array_uint32_le(abstract->data + 7) + EPOCH;
@ -147,7 +161,7 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
divesystem_idive_parser_t *parser = (divesystem_idive_parser_t *) abstract;
const unsigned char *data = abstract->data;
if (abstract->size < SZ_HEADER)
if (abstract->size < parser->headersize)
return DC_STATUS_DATAFORMAT;
if (!parser->cached) {
@ -201,8 +215,8 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
unsigned int o2_previous = 0xFFFFFFFF;
unsigned int he_previous = 0xFFFFFFFF;
unsigned int offset = SZ_HEADER;
while (offset + SZ_SAMPLE <= size) {
unsigned int offset = parser->headersize;
while (offset + parser->samplesize <= size) {
dc_sample_value_t sample = {0};
// Time (seconds).
@ -250,11 +264,15 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
ngasmixes = i + 1;
}
sample.gasmix = i;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
sample.event.type = SAMPLE_EVENT_GASCHANGE2;
sample.event.time = 0;
sample.event.flags = 0;
sample.event.value = o2 | (he << 16);
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
#endif
o2_previous = o2;
he_previous = he;
}
@ -279,7 +297,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
sample.cns = cns / 100.0;
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
offset += SZ_SAMPLE;
offset += parser->samplesize;
}
// Cache the data for later use.

View File

@ -70,6 +70,7 @@ static dc_status_t hw_frog_device_foreach (dc_device_t *abstract, dc_dive_callba
static dc_status_t hw_frog_device_close (dc_device_t *abstract);
static const dc_device_vtable_t hw_frog_device_vtable = {
sizeof(hw_frog_device_t),
DC_FAMILY_HW_FROG,
hw_frog_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -202,19 +203,19 @@ hw_frog_transfer (hw_frog_device_t *device,
dc_status_t
hw_frog_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
hw_frog_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
hw_frog_device_t *device = (hw_frog_device_t *) malloc (sizeof (hw_frog_device_t));
device = (hw_frog_device_t *) dc_device_allocate (context, &hw_frog_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &hw_frog_device_vtable);
// Set the default values.
device->port = NULL;
memset (device->fingerprint, 0, sizeof (device->fingerprint));
@ -223,25 +224,23 @@ hw_frog_device_open (dc_device_t **out, dc_context_t *context, const char *name)
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (115200 8N1).
rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (3000ms).
if (serial_set_timeout (device->port, 3000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -249,44 +248,44 @@ hw_frog_device_open (dc_device_t **out, dc_context_t *context, const char *name)
serial_flush (device->port, SERIAL_QUEUE_BOTH);
// Send the init command.
dc_status_t status = hw_frog_transfer (device, NULL, INIT, NULL, 0, NULL, 0);
status = hw_frog_transfer (device, NULL, INIT, NULL, 0, NULL, 0);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to send the command.");
serial_close (device->port);
free (device);
return status;
goto error_close;
}
*out = (dc_device_t *) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
hw_frog_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
hw_frog_device_t *device = (hw_frog_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
// Send the exit command.
dc_status_t status = hw_frog_transfer (device, NULL, EXIT, NULL, 0, NULL, 0);
if (status != DC_STATUS_SUCCESS) {
rc = hw_frog_transfer (device, NULL, EXIT, NULL, 0, NULL, 0);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command.");
serial_close (device->port);
free (device);
return status;
dc_status_set_error(&status, rc);
}
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -79,6 +79,7 @@ static dc_status_t hw_ostc_device_foreach (dc_device_t *abstract, dc_dive_callba
static dc_status_t hw_ostc_device_close (dc_device_t *abstract);
static const dc_device_vtable_t hw_ostc_device_vtable = {
sizeof(hw_ostc_device_t),
DC_FAMILY_HW_OSTC,
hw_ostc_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -125,19 +126,19 @@ hw_ostc_send (hw_ostc_device_t *device, unsigned char cmd, unsigned int echo)
dc_status_t
hw_ostc_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
hw_ostc_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
hw_ostc_device_t *device = (hw_ostc_device_t *) malloc (sizeof (hw_ostc_device_t));
device = (hw_ostc_device_t *) dc_device_allocate (context, &hw_ostc_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &hw_ostc_device_vtable);
// Set the default values.
device->port = NULL;
memset (device->fingerprint, 0, sizeof (device->fingerprint));
@ -146,25 +147,23 @@ hw_ostc_device_open (dc_device_t **out, dc_context_t *context, const char *name)
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (115200 8N1).
rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data.
if (serial_set_timeout (device->port, 4000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -174,24 +173,27 @@ hw_ostc_device_open (dc_device_t **out, dc_context_t *context, const char *name)
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
hw_ostc_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
hw_ostc_device_t *device = (hw_ostc_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -124,6 +124,7 @@ static dc_status_t hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callb
static dc_status_t hw_ostc3_device_close (dc_device_t *abstract);
static const dc_device_vtable_t hw_ostc3_device_vtable = {
sizeof(hw_ostc3_device_t),
DC_FAMILY_HW_OSTC3,
hw_ostc3_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -276,19 +277,19 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
dc_status_t
hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
hw_ostc3_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
hw_ostc3_device_t *device = (hw_ostc3_device_t *) malloc (sizeof (hw_ostc3_device_t));
device = (hw_ostc3_device_t *) dc_device_allocate (context, &hw_ostc3_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &hw_ostc3_device_vtable);
// Set the default values.
device->serial = NULL;
memset (device->fingerprint, 0, sizeof (device->fingerprint));
@ -297,25 +298,23 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name
int rc = dc_serial_native_open (&device->serial, context, name);
if (rc != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to open the serial port.");
free (device);
return rc;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (115200 8N1).
rc = serial_configure (device->serial->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
device->serial->ops->close (device->serial->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (3000ms).
if (serial_set_timeout (device->serial->port, 3000) == -1) {
ERROR (context, "Failed to set the timeout.");
device->serial->ops->close (device->serial->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -327,12 +326,20 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name
*out = (dc_device_t *) device;
return DC_STATUS_SUCCESS;
error_close:
device->serial->ops->close (device->serial->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
dc_status_t
hw_ostc3_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial_t *serial)
{
dc_status_t status = DC_STATUS_SUCCESS;
if (out == NULL || serial == NULL || serial->port == NULL)
return DC_STATUS_INVALIDARGS;
@ -343,9 +350,6 @@ hw_ostc3_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &hw_ostc3_device_vtable);
// Set the default values.
memset (device->fingerprint, 0, sizeof (device->fingerprint));
@ -357,18 +361,17 @@ hw_ostc3_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial
int rc = serial_configure (device->serial->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
device->serial->ops->close (device->serial->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
}
// Set the timeout for receiving data (3000ms).
if (device->serial->ops->set_timeout (device->serial->port, 3000) == -1) {
ERROR (context, "Failed to set the timeout.");
device->serial->ops->close (device->serial->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -380,6 +383,12 @@ hw_ostc3_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial
*out = (dc_device_t *) device;
return DC_STATUS_SUCCESS;
error_close:
device->serial->ops->close (device->serial->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
@ -434,7 +443,7 @@ hw_ostc3_device_init_service (hw_ostc3_device_t *device)
output[2] != 0xCD || output[3] != 0xEF ||
output[4] != S_READY) {
ERROR (context, "Failed to verify echo.");
return DC_STATUS_IO;
return DC_STATUS_PROTOCOL;
}
device->state = SERVICE;
@ -477,6 +486,7 @@ hw_ostc3_device_init (hw_ostc3_device_t *device, hw_ostc3_state_t state)
static dc_status_t
hw_ostc3_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
hw_ostc3_device_t *device = (hw_ostc3_device_t*) abstract;
dc_status_t rc = DC_STATUS_SUCCESS;
@ -486,21 +496,16 @@ hw_ostc3_device_close (dc_device_t *abstract)
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command.");
device->serial->ops->close (device->serial->port);
free (device);
return rc;
dc_status_set_error(&status, rc);
}
}
// Close the device.
if (device->serial->ops->close (device->serial->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}
@ -1065,7 +1070,7 @@ hw_ostc3_firmware_readfile (hw_ostc3_firmware_t *firmware, dc_context_t *context
if (firmware->checksum != hw_ostc3_firmware_checksum (firmware)) {
ERROR (context, "Failed to verify file checksum.");
return DC_STATUS_IO;
return DC_STATUS_DATAFORMAT;
}
return DC_STATUS_SUCCESS;

View File

@ -39,6 +39,8 @@
#define MAXCONFIG 7
#define NGASMIXES 15
#define UNDEFINED 0xFF
#define ALL 0
#define FIXED 1
#define MANUAL 2
@ -115,15 +117,15 @@ static dc_status_t hw_ostc_parser_set_data (dc_parser_t *abstract, const unsigne
static dc_status_t hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t hw_ostc_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t hw_ostc_parser_vtable = {
sizeof(hw_ostc_parser_t),
DC_FAMILY_HW_OSTC,
hw_ostc_parser_set_data, /* set_data */
hw_ostc_parser_get_datetime, /* datetime */
hw_ostc_parser_get_field, /* fields */
hw_ostc_parser_samples_foreach, /* samples_foreach */
hw_ostc_parser_destroy /* destroy */
NULL /* destroy */
};
static const hw_ostc_layout_t hw_ostc_layout_ostc = {
@ -247,7 +249,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
}
// Get all the gas mixes, and the index of the inital mix.
unsigned int initial = 0;
unsigned int initial = UNDEFINED;
unsigned int ngasmixes = 0;
hw_ostc_gasmix_t gasmix[NGASMIXES] = {{0}};
if (version == 0x22) {
@ -263,7 +265,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
gasmix[i].oxygen = data[28 + 4 * i + 0];
gasmix[i].helium = data[28 + 4 * i + 1];
// Find the first gas marked as the initial gas.
if (!initial && data[28 + 4 * i + 3] == 1) {
if (initial == UNDEFINED && data[28 + 4 * i + 3] == 1) {
initial = i + 1; /* One based index! */
}
}
@ -275,7 +277,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
gasmix[i].helium = data[19 + 2 * i + 1];
}
}
if (initial != 0xFF) {
if (initial != UNDEFINED) {
if (initial < 1 || initial > ngasmixes) {
ERROR(abstract->context, "Invalid initial gas mix.");
return DC_STATUS_DATAFORMAT;
@ -303,19 +305,18 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
dc_status_t
hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int frog)
{
hw_ostc_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
hw_ostc_parser_t *parser = (hw_ostc_parser_t *) malloc (sizeof (hw_ostc_parser_t));
parser = (hw_ostc_parser_t *) dc_parser_allocate (context, &hw_ostc_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &hw_ostc_parser_vtable);
// Set the default values.
parser->frog = frog;
parser->cached = 0;
@ -337,16 +338,6 @@ hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int se
}
static dc_status_t
hw_ostc_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
hw_ostc_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
@ -707,7 +698,10 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Initial gas mix.
if (time == samplerate && parser->initial != 0xFF) {
if (time == samplerate && parser->initial != UNDEFINED) {
sample.gasmix = parser->initial;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
unsigned int idx = parser->initial;
unsigned int o2 = parser->gasmix[idx].oxygen;
unsigned int he = parser->gasmix[idx].helium;
@ -716,6 +710,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
sample.event.flags = 0;
sample.event.value = o2 | (he << 16);
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
#endif
}
// Depth (mbar).
@ -800,11 +795,16 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
parser->gasmix[idx].helium = he;
parser->ngasmixes = idx + 1;
}
sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
sample.event.type = SAMPLE_EVENT_GASCHANGE2;
sample.event.time = 0;
sample.event.flags = 0;
sample.event.value = o2 | (he << 16);
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
#endif
offset += 2;
length -= 2;
}
@ -821,6 +821,9 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
return DC_STATUS_DATAFORMAT;
}
idx--; /* Convert to a zero based index. */
sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
unsigned int o2 = parser->gasmix[idx].oxygen;
unsigned int he = parser->gasmix[idx].helium;
sample.event.type = SAMPLE_EVENT_GASCHANGE2;
@ -828,6 +831,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
sample.event.flags = 0;
sample.event.value = o2 | (he << 16);
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
#endif
offset++;
length--;
}
@ -851,11 +855,29 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
ERROR (abstract->context, "Buffer overflow detected!");
return DC_STATUS_DATAFORMAT;
}
unsigned int o2 = data[offset];
unsigned int he = data[offset + 1];
unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, MANUAL);
if (idx >= parser->ngasmixes) {
if (idx >= NGASMIXES) {
ERROR (abstract->context, "Maximum number of gas mixes reached.");
return DC_STATUS_NOMEMORY;
}
parser->gasmix[idx].oxygen = o2;
parser->gasmix[idx].helium = he;
parser->ngasmixes = idx + 1;
}
sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
sample.event.type = SAMPLE_EVENT_GASCHANGE2;
sample.event.time = 0;
sample.event.flags = 0;
sample.event.value = data[offset] | (data[offset + 1] << 16);
sample.event.value = o2 | (he << 16);
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
#endif
offset += 2;
length -= 2;
}
@ -941,11 +963,29 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
ERROR (abstract->context, "Buffer overflow detected!");
return DC_STATUS_DATAFORMAT;
}
unsigned int o2 = data[offset];
unsigned int he = data[offset + 1];
unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, MANUAL);
if (idx >= parser->ngasmixes) {
if (idx >= NGASMIXES) {
ERROR (abstract->context, "Maximum number of gas mixes reached.");
return DC_STATUS_NOMEMORY;
}
parser->gasmix[idx].oxygen = o2;
parser->gasmix[idx].helium = he;
parser->ngasmixes = idx + 1;
}
sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
sample.event.type = SAMPLE_EVENT_GASCHANGE2;
sample.event.time = 0;
sample.event.flags = 0;
sample.event.value = data[offset] | (data[offset + 1] << 16);
sample.event.value = o2 | (he << 16);
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
#endif
offset += 2;
length -= 2;
}

View File

@ -43,9 +43,17 @@
#include "array.h"
#ifdef _WIN32
#define ERRNO WSAGetLastError ()
#define S_ERRNO WSAGetLastError ()
#define S_EAGAIN WSAEWOULDBLOCK
#define S_INVALID INVALID_SOCKET
#define S_IOCTL ioctlsocket
#define S_CLOSE closesocket
#else
#define ERRNO errno
#define S_ERRNO errno
#define S_EAGAIN EAGAIN
#define S_INVALID -1
#define S_IOCTL ioctl
#define S_CLOSE close
#endif
#ifdef _MSC_VER
@ -75,7 +83,7 @@ irda_socket_open (irda_t **out, dc_context_t *context)
#ifdef _WIN32
SYSERROR (context, ERROR_OUTOFMEMORY);
#else
SYSERROR (context, errno);
SYSERROR (context, ENOMEM);
#endif
return -1; // ENOMEM (Not enough space)
}
@ -90,10 +98,10 @@ irda_socket_open (irda_t **out, dc_context_t *context)
// Initialize the winsock dll.
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD (2, 2);
if (WSAStartup (wVersionRequested, &wsaData) != 0) {
SYSERROR (context, ERRNO);
free (device);
return -1;
int rc = WSAStartup (wVersionRequested, &wsaData);
if (rc != 0) {
SYSERROR (context, rc);
goto error_free;
}
// Confirm that the winsock dll supports version 2.2.
@ -102,36 +110,36 @@ irda_socket_open (irda_t **out, dc_context_t *context)
if (LOBYTE (wsaData.wVersion) != 2 ||
HIBYTE (wsaData.wVersion) != 2) {
ERROR (context, "Incorrect winsock version.");
WSACleanup ();
free (device);
return -1;
goto error_wsacleanup;
}
#endif
// Open the socket.
device->fd = socket (AF_IRDA, SOCK_STREAM, 0);
#ifdef _WIN32
if (device->fd == INVALID_SOCKET) {
#else
if (device->fd == -1) {
#endif
SYSERROR (context, ERRNO);
#ifdef _WIN32
WSACleanup ();
#endif
free (device);
return -1;
if (device->fd == S_INVALID) {
SYSERROR (context, S_ERRNO);
goto error_wsacleanup;
}
*out = device;
return 0;
error_wsacleanup:
#ifdef _WIN32
WSACleanup ();
error_free:
#endif
free (device);
return -1;
}
int
irda_socket_close (irda_t *device)
{
int errcode = 0;
if (device == NULL)
return -1;
@ -139,32 +147,23 @@ irda_socket_close (irda_t *device)
shutdown (device->fd, 0);
// Close the socket.
#ifdef _WIN32
if (closesocket (device->fd) != 0) {
#else
if (close (device->fd) != 0) {
#endif
SYSERROR (device->context, ERRNO);
#ifdef _WIN32
WSACleanup ();
#endif
free (device);
return -1;
if (S_CLOSE (device->fd) != 0) {
SYSERROR (device->context, S_ERRNO);
errcode = -1;
}
#ifdef _WIN32
// Terminate the winsock dll.
if (WSACleanup () != 0) {
SYSERROR (device->context, ERRNO);
free (device);
return -1;
SYSERROR (device->context, S_ERRNO);
errcode = -1;
}
#endif
// Free memory.
free (device);
return 0;
return errcode;
}
@ -222,12 +221,8 @@ irda_socket_discover (irda_t *device, irda_callback_t callback, void *userdata)
// discovered, while on Windows it succeeds and sets the number
// of devices to zero. Both situations are handled the same here.
if (rc != 0) {
#ifdef _WIN32
if (WSAGetLastError() != WSAEWOULDBLOCK) {
#else
if (errno != EAGAIN) {
#endif
SYSERROR (device->context, ERRNO);
if (S_ERRNO != S_EAGAIN) {
SYSERROR (device->context, S_ERRNO);
return -1; // Error during getsockopt call.
}
}
@ -250,41 +245,25 @@ irda_socket_discover (irda_t *device, irda_callback_t callback, void *userdata)
if (callback) {
#ifdef _WIN32
for (unsigned int i = 0; i < list->numDevice; ++i) {
const char *name = list->Device[i].irdaDeviceName;
unsigned int address = array_uint32_le (list->Device[i].irdaDeviceID);
unsigned int charset = list->Device[i].irdaCharSet;
unsigned int hints = (list->Device[i].irdaDeviceHints1 << 8) +
list->Device[i].irdaDeviceHints2;
INFO (device->context,
"Discover: address=%08x, name=%s, charset=%02x, hints=%04x",
address,
list->Device[i].irdaDeviceName,
list->Device[i].irdaCharSet,
hints);
callback (address,
list->Device[i].irdaDeviceName,
list->Device[i].irdaCharSet,
hints,
userdata);
}
#else
for (unsigned int i = 0; i < list->len; ++i) {
const char *name = list->dev[i].info;
unsigned int address = list->dev[i].daddr;
unsigned int charset = list->dev[i].charset;
unsigned int hints = array_uint16_be (list->dev[i].hints);
#endif
INFO (device->context,
"Discover: address=%08x, name=%s, charset=%02x, hints=%04x",
list->dev[i].daddr,
list->dev[i].info,
list->dev[i].charset,
hints);
address, name, charset, hints);
callback (list->dev[i].daddr,
list->dev[i].info,
list->dev[i].charset,
hints,
userdata);
callback (address, name, charset, hints, userdata);
}
#endif
}
return 0;
@ -321,7 +300,7 @@ irda_socket_connect_name (irda_t *device, unsigned int address, const char *name
#endif
if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) {
SYSERROR (device->context, ERRNO);
SYSERROR (device->context, S_ERRNO);
return -1;
}
@ -353,7 +332,7 @@ irda_socket_connect_lsap (irda_t *device, unsigned int address, unsigned int lsa
#endif
if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) {
SYSERROR (device->context, ERRNO);
SYSERROR (device->context, S_ERRNO);
return -1;
}
@ -369,12 +348,12 @@ irda_socket_available (irda_t *device)
#ifdef _WIN32
unsigned long bytes = 0;
if (ioctlsocket (device->fd, FIONREAD, &bytes) != 0) {
#else
int bytes = 0;
if (ioctl (device->fd, FIONREAD, &bytes) != 0) {
#endif
SYSERROR (device->context, ERRNO);
if (S_IOCTL (device->fd, FIONREAD, &bytes) != 0) {
SYSERROR (device->context, S_ERRNO);
return -1;
}
@ -402,7 +381,7 @@ irda_socket_read (irda_t *device, void *data, unsigned int size)
while (nbytes < size) {
int rc = select (device->fd + 1, &fds, NULL, NULL, (device->timeout >= 0 ? &tv : NULL));
if (rc < 0) {
SYSERROR (device->context, ERRNO);
SYSERROR (device->context, S_ERRNO);
return -1; // Error during select call.
} else if (rc == 0) {
break; // Timeout.
@ -410,7 +389,7 @@ irda_socket_read (irda_t *device, void *data, unsigned int size)
int n = recv (device->fd, (char*) data + nbytes, size - nbytes, 0);
if (n < 0) {
SYSERROR (device->context, ERRNO);
SYSERROR (device->context, S_ERRNO);
return -1; // Error during recv call.
} else if (n == 0) {
break; // EOF reached.
@ -435,7 +414,7 @@ irda_socket_write (irda_t *device, const void *data, unsigned int size)
while (nbytes < size) {
int n = send (device->fd, (char*) data + nbytes, size - nbytes, 0);
if (n < 0) {
SYSERROR (device->context, ERRNO);
SYSERROR (device->context, S_ERRNO);
return -1; // Error during send call.
}

View File

@ -70,6 +70,7 @@ shearwater_petrel_parser_create
diverite_nitekq_parser_create
citizen_aqualand_parser_create
divesystem_idive_parser_create
divesystem_idive_parser_create2
dc_device_open
dc_device_close
@ -178,3 +179,4 @@ diverite_nitekq_device_open
diverite_nitekq_extract_dives
citizen_aqualand_device_open
divesystem_idive_device_open
divesystem_idive_device_open2

View File

@ -52,13 +52,10 @@
#define GAUGE 3
void
mares_common_device_init (mares_common_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable)
mares_common_device_init (mares_common_device_t *device)
{
assert (device != NULL);
// Initialize the base class.
device_init (&device->base, context, vtable);
// Set the default values.
device->port = NULL;
device->echo = 0;

View File

@ -47,7 +47,7 @@ typedef struct mares_common_device_t {
} mares_common_device_t;
void
mares_common_device_init (mares_common_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable);
mares_common_device_init (mares_common_device_t *device);
dc_status_t
mares_common_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size);

View File

@ -63,6 +63,7 @@ static dc_status_t mares_darwin_device_foreach (dc_device_t *abstract, dc_dive_c
static dc_status_t mares_darwin_device_close (dc_device_t *abstract);
static const dc_device_vtable_t mares_darwin_device_vtable = {
sizeof(mares_darwin_device_t),
DC_FAMILY_MARES_DARWIN,
mares_darwin_device_set_fingerprint, /* set_fingerprint */
mares_common_device_read, /* read */
@ -96,18 +97,21 @@ static const mares_darwin_layout_t mares_darwinair_layout = {
dc_status_t
mares_darwin_device_open (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model)
{
dc_status_t status = DC_STATUS_SUCCESS;
mares_darwin_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
mares_darwin_device_t *device = (mares_darwin_device_t *) malloc (sizeof (mares_darwin_device_t));
device = (mares_darwin_device_t *) dc_device_allocate (context, &mares_darwin_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
mares_common_device_init (&device->base, context, &mares_darwin_device_vtable);
mares_common_device_init (&device->base);
// Set the default values.
memset (device->fingerprint, 0, sizeof (device->fingerprint));
@ -121,34 +125,31 @@ mares_darwin_device_open (dc_device_t **out, dc_context_t *context, const char *
int rc = serial_open (&device->base.port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->base.port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->base.port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->base.port, 1000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->base.port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the DTR/RTS lines.
if (serial_set_dtr (device->base.port, 1) == -1 ||
serial_set_rts (device->base.port, 1) == -1) {
ERROR (context, "Failed to set the DTR/RTS line.");
serial_close (device->base.port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -162,23 +163,26 @@ mares_darwin_device_open (dc_device_t **out, dc_context_t *context, const char *
*out = (dc_device_t *) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->base.port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
mares_darwin_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
mares_darwin_device_t *device = (mares_darwin_device_t *) abstract;
// Close the device.
if (serial_close (device->base.port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -47,34 +47,33 @@ static dc_status_t mares_darwin_parser_set_data (dc_parser_t *abstract, const un
static dc_status_t mares_darwin_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t mares_darwin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t mares_darwin_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t mares_darwin_parser_vtable = {
sizeof(mares_darwin_parser_t),
DC_FAMILY_MARES_DARWIN,
mares_darwin_parser_set_data, /* set_data */
mares_darwin_parser_get_datetime, /* datetime */
mares_darwin_parser_get_field, /* fields */
mares_darwin_parser_samples_foreach, /* samples_foreach */
mares_darwin_parser_destroy /* destroy */
NULL /* destroy */
};
dc_status_t
mares_darwin_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{
mares_darwin_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
mares_darwin_parser_t *parser = (mares_darwin_parser_t *) malloc (sizeof (mares_darwin_parser_t));
parser = (mares_darwin_parser_t *) dc_parser_allocate (context, &mares_darwin_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &mares_darwin_parser_vtable);
parser->model = model;
if (model == DARWINAIR) {
@ -91,16 +90,6 @@ mares_darwin_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i
}
static dc_status_t
mares_darwin_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
mares_darwin_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{

View File

@ -84,6 +84,7 @@ static dc_status_t mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_c
static dc_status_t mares_iconhd_device_close (dc_device_t *abstract);
static const dc_device_vtable_t mares_iconhd_device_vtable = {
sizeof(mares_iconhd_device_t),
DC_FAMILY_MARES_ICONHD,
mares_iconhd_device_set_fingerprint, /* set_fingerprint */
mares_iconhd_device_read, /* read */
@ -214,19 +215,19 @@ mares_iconhd_transfer (mares_iconhd_device_t *device,
dc_status_t
mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model)
{
dc_status_t status = DC_STATUS_SUCCESS;
mares_iconhd_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
mares_iconhd_device_t *device = (mares_iconhd_device_t *) malloc (sizeof (mares_iconhd_device_t));
device = (mares_iconhd_device_t *) dc_device_allocate (context, &mares_iconhd_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &mares_iconhd_device_vtable);
// Set the default values.
device->port = NULL;
device->layout = NULL;
@ -239,25 +240,23 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char *
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (115200 8E1).
rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_EVEN, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->port, 1000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the DTR/RTS lines.
@ -265,9 +264,8 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char *
serial_set_rts (device->port, 0) == -1)
{
ERROR (context, "Failed to set the DTR/RTS line.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -275,12 +273,10 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char *
// Send the version command.
unsigned char command[] = {0xC2, 0x67};
dc_status_t status = mares_iconhd_transfer (device, command, sizeof (command),
status = mares_iconhd_transfer (device, command, sizeof (command),
device->version, sizeof (device->version));
if (status != DC_STATUS_SUCCESS) {
serial_close (device->port);
free (device);
return status;
goto error_close;
}
// Autodetect the model using the version packet.
@ -314,24 +310,27 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char *
*out = (dc_device_t *) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
mares_iconhd_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
mares_iconhd_device_t *device = (mares_iconhd_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -60,15 +60,15 @@ static dc_status_t mares_iconhd_parser_set_data (dc_parser_t *abstract, const un
static dc_status_t mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t mares_iconhd_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t mares_iconhd_parser_vtable = {
sizeof(mares_iconhd_parser_t),
DC_FAMILY_MARES_ICONHD,
mares_iconhd_parser_set_data, /* set_data */
mares_iconhd_parser_get_datetime, /* datetime */
mares_iconhd_parser_get_field, /* fields */
mares_iconhd_parser_samples_foreach, /* samples_foreach */
mares_iconhd_parser_destroy /* destroy */
NULL /* destroy */
};
static dc_status_t
@ -198,19 +198,18 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser)
dc_status_t
mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{
mares_iconhd_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
mares_iconhd_parser_t *parser = (mares_iconhd_parser_t *) malloc (sizeof (mares_iconhd_parser_t));
parser = (mares_iconhd_parser_t *) dc_parser_allocate (context, &mares_iconhd_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &mares_iconhd_parser_vtable);
// Set the default values.
parser->model = model;
parser->cached = 0;
@ -229,16 +228,6 @@ mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i
}
static dc_status_t
mares_iconhd_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
mares_iconhd_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
@ -510,10 +499,14 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
return DC_STATUS_DATAFORMAT;
}
if (gasmix != gasmix_previous) {
sample.gasmix = gasmix;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
sample.event.type = SAMPLE_EVENT_GASCHANGE;
sample.event.time = 0;
sample.event.value = parser->oxygen[gasmix];
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
#endif
gasmix_previous = gasmix;
}
}

View File

@ -61,6 +61,7 @@ static dc_status_t mares_nemo_device_foreach (dc_device_t *abstract, dc_dive_cal
static dc_status_t mares_nemo_device_close (dc_device_t *abstract);
static const dc_device_vtable_t mares_nemo_device_vtable = {
sizeof(mares_nemo_device_t),
DC_FAMILY_MARES_NEMO,
mares_nemo_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -90,19 +91,19 @@ static const mares_common_layout_t mares_nemo_apneist_layout = {
dc_status_t
mares_nemo_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
mares_nemo_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
mares_nemo_device_t *device = (mares_nemo_device_t *) malloc (sizeof (mares_nemo_device_t));
device = (mares_nemo_device_t *) dc_device_allocate (context, &mares_nemo_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &mares_nemo_device_vtable);
// Set the default values.
device->port = NULL;
memset (device->fingerprint, 0, sizeof (device->fingerprint));
@ -111,34 +112,31 @@ mares_nemo_device_open (dc_device_t **out, dc_context_t *context, const char *na
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->port, 1000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the DTR/RTS lines.
if (serial_set_dtr (device->port, 1) == -1 ||
serial_set_rts (device->port, 1) == -1) {
ERROR (context, "Failed to set the DTR/RTS line.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -147,24 +145,27 @@ mares_nemo_device_open (dc_device_t **out, dc_context_t *context, const char *na
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
mares_nemo_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
mares_nemo_device_t *device = (mares_nemo_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -63,34 +63,33 @@ static dc_status_t mares_nemo_parser_set_data (dc_parser_t *abstract, const unsi
static dc_status_t mares_nemo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t mares_nemo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t mares_nemo_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t mares_nemo_parser_vtable = {
sizeof(mares_nemo_parser_t),
DC_FAMILY_MARES_NEMO,
mares_nemo_parser_set_data, /* set_data */
mares_nemo_parser_get_datetime, /* datetime */
mares_nemo_parser_get_field, /* fields */
mares_nemo_parser_samples_foreach, /* samples_foreach */
mares_nemo_parser_destroy /* destroy */
NULL /* destroy */
};
dc_status_t
mares_nemo_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{
mares_nemo_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
mares_nemo_parser_t *parser = (mares_nemo_parser_t *) malloc (sizeof (mares_nemo_parser_t));
parser = (mares_nemo_parser_t *) dc_parser_allocate (context, &mares_nemo_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &mares_nemo_parser_vtable);
// Get the freedive mode for this model.
unsigned int freedive = FREEDIVE;
if (model == NEMOWIDE || model == NEMOAIR || model == PUCK || model == PUCKAIR)
@ -112,16 +111,6 @@ mares_nemo_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int
}
static dc_status_t
mares_nemo_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
mares_nemo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{

View File

@ -51,6 +51,7 @@ static dc_status_t mares_puck_device_foreach (dc_device_t *abstract, dc_dive_cal
static dc_status_t mares_puck_device_close (dc_device_t *abstract);
static const dc_device_vtable_t mares_puck_device_vtable = {
sizeof(mares_puck_device_t),
DC_FAMILY_MARES_PUCK,
mares_puck_device_set_fingerprint, /* set_fingerprint */
mares_common_device_read, /* read */
@ -88,18 +89,21 @@ static const mares_common_layout_t mares_nemowide_layout = {
dc_status_t
mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
mares_puck_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
mares_puck_device_t *device = (mares_puck_device_t *) malloc (sizeof (mares_puck_device_t));
device = (mares_puck_device_t *) dc_device_allocate (context, &mares_puck_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
mares_common_device_init (&device->base, context, &mares_puck_device_vtable);
mares_common_device_init (&device->base);
// Set the default values.
device->layout = NULL;
@ -109,34 +113,31 @@ mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *na
int rc = serial_open (&device->base.port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (38400 8N1).
rc = serial_configure (device->base.port, 38400, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->base.port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->base.port, 1000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->base.port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Clear the DTR/RTS lines.
if (serial_set_dtr (device->base.port, 0) == -1 ||
serial_set_rts (device->base.port, 0) == -1) {
ERROR (context, "Failed to set the DTR/RTS line.");
serial_close (device->base.port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -144,11 +145,9 @@ mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *na
// Identify the model number.
unsigned char header[PACKETSIZE] = {0};
dc_status_t status = mares_common_device_read ((dc_device_t *) device, 0, header, sizeof (header));
status = mares_common_device_read ((dc_device_t *) device, 0, header, sizeof (header));
if (status != DC_STATUS_SUCCESS) {
serial_close (device->base.port);
free (device);
return status;
goto error_close;
}
// Override the base class values.
@ -171,24 +170,27 @@ mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *na
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->base.port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
mares_puck_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
mares_puck_device_t *device = (mares_puck_device_t*) abstract;
// Close the device.
if (serial_close (device->base.port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -71,6 +71,7 @@ static dc_status_t oceanic_atom2_device_write (dc_device_t *abstract, unsigned i
static dc_status_t oceanic_atom2_device_close (dc_device_t *abstract);
static const dc_device_vtable_t oceanic_atom2_device_vtable = {
sizeof(oceanic_atom2_device_t),
DC_FAMILY_OCEANIC_ATOM2,
oceanic_common_device_set_fingerprint, /* set_fingerprint */
oceanic_atom2_device_read, /* read */
@ -85,7 +86,8 @@ static const oceanic_common_version_t aeris_f10_version[] = {
};
static const oceanic_common_version_t aeris_f11_version[] = {
{"AERISF11 \0\0 1024"},
{"AERISF11 \0\0 1024"},
{"OCEANF11 \0\0 1024"},
};
static const oceanic_common_version_t oceanic_atom1_version[] = {
@ -196,9 +198,9 @@ static const oceanic_common_layout_t aeris_f11_layout = {
0x0000, /* cf_devinfo */
0x0040, /* cf_pointers */
0x0100, /* rb_logbook_begin */
0x0AC0, /* rb_logbook_end */
0x0D80, /* rb_logbook_end */
32, /* rb_logbook_entry_size */
0xD810, /* rb_profile_begin */
0x0D80, /* rb_profile_begin */
0x20000, /* rb_profile_end */
0, /* pt_mode_global */
3 /* pt_mode_logbook */
@ -520,20 +522,22 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char
dc_status_t
oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model)
{
dc_status_t status = DC_STATUS_SUCCESS;
oceanic_atom2_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
oceanic_atom2_device_t *device = (oceanic_atom2_device_t *) malloc (sizeof (oceanic_atom2_device_t));
device = (oceanic_atom2_device_t *) dc_device_allocate (context, &oceanic_atom2_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
oceanic_common_device_init (&device->base, context, &oceanic_atom2_device_vtable);
oceanic_common_device_init (&device->base);
// Set the default values.
device->port = NULL;
@ -546,8 +550,8 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Get the correct baudrate.
@ -560,17 +564,15 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char
rc = serial_configure (device->port, baudrate, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->port, 1000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Give the interface 100 ms to settle and draw power up.
@ -586,11 +588,9 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char
// Switch the device from surface mode into download mode. Before sending
// this command, the device needs to be in PC mode (automatically activated
// by connecting the device), or already in download mode.
dc_status_t status = oceanic_atom2_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version));
status = oceanic_atom2_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version));
if (status != DC_STATUS_SUCCESS) {
serial_close (device->port);
free (device);
return status;
goto error_close;
}
// Override the base class values.
@ -641,12 +641,19 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
oceanic_atom2_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
oceanic_atom2_device_t *device = (oceanic_atom2_device_t*) abstract;
// Send the quit command.
@ -654,14 +661,10 @@ oceanic_atom2_device_close (dc_device_t *abstract)
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -72,9 +72,10 @@
#define AMPHOS 0x4545
#define AMPHOSAIR 0x4546
#define PROPLUS3 0x4548
#define F11 0x4549
#define F11A 0x4549
#define OCI 0x454B
#define A300CS 0x454C
#define F11B 0x4554
#define VTX 0x4557
#define NORMAL 0
@ -110,34 +111,33 @@ static dc_status_t oceanic_atom2_parser_set_data (dc_parser_t *abstract, const u
static dc_status_t oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t oceanic_atom2_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t oceanic_atom2_parser_vtable = {
sizeof(oceanic_atom2_parser_t),
DC_FAMILY_OCEANIC_ATOM2,
oceanic_atom2_parser_set_data, /* set_data */
oceanic_atom2_parser_get_datetime, /* datetime */
oceanic_atom2_parser_get_field, /* fields */
oceanic_atom2_parser_samples_foreach, /* samples_foreach */
oceanic_atom2_parser_destroy /* destroy */
NULL /* destroy */
};
dc_status_t
oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model, unsigned int serial)
{
oceanic_atom2_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
oceanic_atom2_parser_t *parser = (oceanic_atom2_parser_t *) malloc (sizeof (oceanic_atom2_parser_t));
parser = (oceanic_atom2_parser_t *) dc_parser_allocate (context, &oceanic_atom2_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &oceanic_atom2_parser_vtable);
// Set the default values.
parser->model = model;
parser->headersize = 9 * PAGESIZE / 2;
@ -157,10 +157,10 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
parser->headersize -= 2 * PAGESIZE;
} else if (model == F10) {
parser->headersize = 3 * PAGESIZE;
parser->footersize = PAGESIZE / 2;
} else if (model == F11) {
parser->footersize = 0;
} else if (model == F11A || model == F11B) {
parser->headersize = 5 * PAGESIZE;
parser->footersize = PAGESIZE / 2;
parser->footersize = 0;
} else if (model == A300CS || model == VTX) {
parser->headersize = 5 * PAGESIZE;
}
@ -184,16 +184,6 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
}
static dc_status_t
oceanic_atom2_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
oceanic_atom2_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
@ -222,7 +212,8 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim
oceanic_atom2_parser_t *parser = (oceanic_atom2_parser_t *) abstract;
unsigned int header = 8;
if (parser->model == F10 || parser->model == F11)
if (parser->model == F10 || parser->model == F11A ||
parser->model == F11B)
header = 32;
if (abstract->size < header)
@ -255,6 +246,12 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim
case VEO20:
case VEO30:
case DG03:
case T3A:
case T3B:
case GEO20:
case PROPLUS3:
case DATAMASK:
case COMPUMASK:
datetime->year = ((p[3] & 0xE0) >> 1) + (p[4] & 0x0F) + 2000;
datetime->month = (p[4] & 0xF0) >> 4;
datetime->day = p[3] & 0x1F;
@ -265,14 +262,15 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim
case AMPHOS:
case AMPHOSAIR:
case VOYAGER2G:
datetime->year = (p[3] & 0x0F) + 2000;
datetime->year = (p[3] & 0x1F) + 2000;
datetime->month = (p[7] & 0xF0) >> 4;
datetime->day = ((p[3] & 0x80) >> 3) + ((p[5] & 0xF0) >> 4);
datetime->hour = bcd2dec (p[1] & 0x1F);
datetime->minute = bcd2dec (p[0]);
break;
case F10:
case F11:
case F11A:
case F11B:
datetime->year = bcd2dec (p[6]) + 2000;
datetime->month = bcd2dec (p[7]);
datetime->day = bcd2dec (p[8]);
@ -298,11 +296,7 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim
default:
datetime->year = bcd2dec (((p[3] & 0xC0) >> 2) + (p[4] & 0x0F)) + 2000;
datetime->month = (p[4] & 0xF0) >> 4;
if (parser->model == T3A || parser->model == T3B ||
parser->model == GEO20 || parser->model == PROPLUS3)
datetime->day = p[3] & 0x3F;
else
datetime->day = bcd2dec (p[3] & 0x3F);
datetime->day = bcd2dec (p[3] & 0x3F);
datetime->hour = bcd2dec (p[1] & 0x1F);
datetime->minute = bcd2dec (p[0]);
break;
@ -377,7 +371,8 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
// Get the dive mode.
unsigned int mode = NORMAL;
if (parser->model == F10 || parser->model == F11) {
if (parser->model == F10 || parser->model == F11A ||
parser->model == F11B) {
mode = FREEDIVE;
} else if (parser->model == T3B || parser->model == VT3 ||
parser->model == DG03) {
@ -481,13 +476,15 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
if (value) {
switch (type) {
case DC_FIELD_DIVETIME:
if (parser->model == F10 || parser->model == F11)
*((unsigned int *) value) = bcd2dec (data[2]) + bcd2dec (data[3]) * 60 + bcd2dec (data[1]) * 3600;
if (parser->model == F10 || parser->model == F11A ||
parser->model == F11B)
*((unsigned int *) value) = bcd2dec (data[2]) + bcd2dec (data[3]) * 60;
else
*((unsigned int *) value) = parser->divetime;
break;
case DC_FIELD_MAXDEPTH:
if (parser->model == F10 || parser->model == F11)
if (parser->model == F10 || parser->model == F11A ||
parser->model == F11B)
*((double *) value) = array_uint16_le (data + 4) / 16.0 * FEET;
else
*((double *) value) = array_uint16_le (data + parser->footer + 4) / 16.0 * FEET;
@ -563,6 +560,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
unsigned int time = 0;
unsigned int interval = 1;
unsigned int samplerate = 1;
if (parser->mode != FREEDIVE) {
unsigned int idx = 0x17;
if (parser->model == A300CS || parser->model == VTX)
@ -581,11 +579,36 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
interval = 60;
break;
}
} else if (parser->model == F11A || parser->model == F11B) {
unsigned int idx = 0x29;
switch (data[idx] & 0x03) {
case 0:
interval = 1;
samplerate = 4;
break;
case 1:
interval = 1;
samplerate = 2;
break;
case 2:
interval = 1;
break;
case 3:
interval = 2;
break;
}
if (samplerate > 1) {
// Some models supports multiple samples per second.
// Since our smallest unit of time is one second, we can't
// represent this, and the extra samples will get dropped.
WARNING(abstract->context, "Multiple samples per second are not supported!");
}
}
unsigned int samplesize = PAGESIZE / 2;
if (parser->mode == FREEDIVE) {
if (parser->model == F10 || parser->model == F11) {
if (parser->model == F10 || parser->model == F11A ||
parser->model == F11B) {
samplesize = 2;
} else {
samplesize = 4;
@ -636,7 +659,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
dc_sample_value_t sample = {0};
// Ignore empty samples.
if (array_isequal (data + offset, samplesize, 0x00) ||
if ((parser->mode != FREEDIVE &&
array_isequal (data + offset, samplesize, 0x00)) ||
array_isequal (data + offset, samplesize, 0xFF)) {
offset += samplesize;
continue;
@ -658,7 +682,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
// The sample size is usually fixed, but some sample types have a
// larger size. Check whether we have that many bytes available.
unsigned int length = samplesize;
unsigned int length = samplesize * samplerate;
if (sampletype == 0xBB) {
length = PAGESIZE;
if (offset + length > size - PAGESIZE)
@ -796,6 +820,9 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
ERROR (abstract->context, "Invalid gas mix index (%u).", gasmix);
return DC_STATUS_DATAFORMAT;
}
sample.gasmix = gasmix - 1;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
unsigned int o2 = parser->oxygen[gasmix - 1];
unsigned int he = parser->helium[gasmix - 1];
sample.event.type = SAMPLE_EVENT_GASCHANGE2;
@ -803,6 +830,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
sample.event.flags = 0;
sample.event.value = o2 | (he << 16);
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
#endif
gasmix_previous = gasmix;
}

View File

@ -125,13 +125,10 @@ oceanic_common_match (const unsigned char *version, const oceanic_common_version
void
oceanic_common_device_init (oceanic_common_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable)
oceanic_common_device_init (oceanic_common_device_t *device)
{
assert (device != NULL);
// Initialize the base class.
device_init (&device->base, context, vtable);
// Set the default values.
memset (device->version, 0, sizeof (device->version));
memset (device->fingerprint, 0, sizeof (device->fingerprint));

View File

@ -71,7 +71,7 @@ int
oceanic_common_match (const unsigned char *version, const oceanic_common_version_t patterns[], unsigned int n);
void
oceanic_common_device_init (oceanic_common_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable);
oceanic_common_device_init (oceanic_common_device_t *device);
dc_status_t
oceanic_common_device_set_fingerprint (dc_device_t *device, const unsigned char data[], unsigned int size);

View File

@ -54,6 +54,7 @@ static dc_status_t oceanic_veo250_device_read (dc_device_t *abstract, unsigned i
static dc_status_t oceanic_veo250_device_close (dc_device_t *abstract);
static const dc_device_vtable_t oceanic_veo250_device_vtable = {
sizeof(oceanic_veo250_device_t),
DC_FAMILY_OCEANIC_VEO250,
oceanic_common_device_set_fingerprint, /* set_fingerprint */
oceanic_veo250_device_read, /* read */
@ -221,18 +222,21 @@ oceanic_veo250_quit (oceanic_veo250_device_t *device)
dc_status_t
oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
oceanic_veo250_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
oceanic_veo250_device_t *device = (oceanic_veo250_device_t *) malloc (sizeof (oceanic_veo250_device_t));
device = (oceanic_veo250_device_t *) dc_device_allocate (context, &oceanic_veo250_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
oceanic_common_device_init (&device->base, context, &oceanic_veo250_device_vtable);
oceanic_common_device_init (&device->base);
// Override the base class values.
device->base.layout = &oceanic_veo250_layout;
@ -246,34 +250,31 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (3000 ms).
if (serial_set_timeout (device->port, 3000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the DTR and RTS lines.
if (serial_set_dtr (device->port, 1) == -1 ||
serial_set_rts (device->port, 1) == -1) {
ERROR (context, "Failed to set the DTR/RTS line.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Give the interface 100 ms to settle and draw power up.
@ -283,11 +284,9 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char
serial_flush (device->port, SERIAL_QUEUE_BOTH);
// Initialize the data cable (PPS mode).
dc_status_t status = oceanic_veo250_init (device);
status = oceanic_veo250_init (device);
if (status != DC_STATUS_SUCCESS) {
serial_close (device->port);
free (device);
return status;
goto error_close;
}
// Delay the sending of the version command.
@ -298,20 +297,25 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char
// the user), or already in download mode.
status = oceanic_veo250_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version));
if (status != DC_STATUS_SUCCESS) {
serial_close (device->port);
free (device);
return status;
goto error_close;
}
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
oceanic_veo250_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
oceanic_veo250_device_t *device = (oceanic_veo250_device_t*) abstract;
// Switch the device back to surface mode.
@ -319,14 +323,10 @@ oceanic_veo250_device_close (dc_device_t *abstract)
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -51,34 +51,33 @@ static dc_status_t oceanic_veo250_parser_set_data (dc_parser_t *abstract, const
static dc_status_t oceanic_veo250_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t oceanic_veo250_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t oceanic_veo250_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t oceanic_veo250_parser_vtable = {
sizeof(oceanic_veo250_parser_t),
DC_FAMILY_OCEANIC_VEO250,
oceanic_veo250_parser_set_data, /* set_data */
oceanic_veo250_parser_get_datetime, /* datetime */
oceanic_veo250_parser_get_field, /* fields */
oceanic_veo250_parser_samples_foreach, /* samples_foreach */
oceanic_veo250_parser_destroy /* destroy */
NULL /* destroy */
};
dc_status_t
oceanic_veo250_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{
oceanic_veo250_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
oceanic_veo250_parser_t *parser = (oceanic_veo250_parser_t *) malloc (sizeof (oceanic_veo250_parser_t));
parser = (oceanic_veo250_parser_t *) dc_parser_allocate (context, &oceanic_veo250_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &oceanic_veo250_parser_vtable);
// Set the default values.
parser->model = model;
parser->cached = 0;
@ -91,16 +90,6 @@ oceanic_veo250_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
}
static dc_status_t
oceanic_veo250_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
oceanic_veo250_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{

View File

@ -54,6 +54,7 @@ static dc_status_t oceanic_vtpro_device_read (dc_device_t *abstract, unsigned in
static dc_status_t oceanic_vtpro_device_close (dc_device_t *abstract);
static const dc_device_vtable_t oceanic_vtpro_device_vtable = {
sizeof(oceanic_vtpro_device_t),
DC_FAMILY_OCEANIC_VTPRO,
oceanic_common_device_set_fingerprint, /* set_fingerprint */
oceanic_vtpro_device_read, /* read */
@ -254,18 +255,21 @@ oceanic_vtpro_calibrate (oceanic_vtpro_device_t *device)
dc_status_t
oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
oceanic_vtpro_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) malloc (sizeof (oceanic_vtpro_device_t));
device = (oceanic_vtpro_device_t *) dc_device_allocate (context, &oceanic_vtpro_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
oceanic_common_device_init (&device->base, context, &oceanic_vtpro_device_vtable);
oceanic_common_device_init (&device->base);
// Override the base class values.
device->base.multipage = MULTIPAGE;
@ -277,34 +281,31 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (3000 ms).
if (serial_set_timeout (device->port, 3000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the DTR and RTS lines.
if (serial_set_dtr (device->port, 1) == -1 ||
serial_set_rts (device->port, 1) == -1) {
ERROR (context, "Failed to set the DTR/RTS line.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Give the interface 100 ms to settle and draw power up.
@ -314,11 +315,9 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char
serial_flush (device->port, SERIAL_QUEUE_BOTH);
// Initialize the data cable (MOD mode).
dc_status_t status = oceanic_vtpro_init (device);
status = oceanic_vtpro_init (device);
if (status != DC_STATUS_SUCCESS) {
serial_close (device->port);
free (device);
return status;
goto error_close;
}
// Switch the device from surface mode into download mode. Before sending
@ -326,9 +325,7 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char
// the user), or already in download mode.
status = oceanic_vtpro_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version));
if (status != DC_STATUS_SUCCESS) {
serial_close (device->port);
free (device);
return status;
goto error_close;
}
// Calibrate the device. Although calibration is optional, it's highly
@ -336,9 +333,7 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char
// when processing the command itself is quite slow.
status = oceanic_vtpro_calibrate (device);
if (status != DC_STATUS_SUCCESS) {
serial_close (device->port);
free (device);
return status;
goto error_close;
}
// Override the base class values.
@ -351,12 +346,19 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
oceanic_vtpro_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t*) abstract;
// Switch the device back to surface mode.
@ -364,14 +366,10 @@ oceanic_vtpro_device_close (dc_device_t *abstract)
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -45,34 +45,33 @@ static dc_status_t oceanic_vtpro_parser_set_data (dc_parser_t *abstract, const u
static dc_status_t oceanic_vtpro_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t oceanic_vtpro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t oceanic_vtpro_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t oceanic_vtpro_parser_vtable = {
sizeof(oceanic_vtpro_parser_t),
DC_FAMILY_OCEANIC_VTPRO,
oceanic_vtpro_parser_set_data, /* set_data */
oceanic_vtpro_parser_get_datetime, /* datetime */
oceanic_vtpro_parser_get_field, /* fields */
oceanic_vtpro_parser_samples_foreach, /* samples_foreach */
oceanic_vtpro_parser_destroy /* destroy */
NULL /* destroy */
};
dc_status_t
oceanic_vtpro_parser_create (dc_parser_t **out, dc_context_t *context)
{
oceanic_vtpro_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
oceanic_vtpro_parser_t *parser = (oceanic_vtpro_parser_t *) malloc (sizeof (oceanic_vtpro_parser_t));
parser = (oceanic_vtpro_parser_t *) dc_parser_allocate (context, &oceanic_vtpro_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &oceanic_vtpro_parser_vtable);
// Set the default values.
parser->cached = 0;
parser->divetime = 0;
@ -84,16 +83,6 @@ oceanic_vtpro_parser_create (dc_parser_t **out, dc_context_t *context)
}
static dc_status_t
oceanic_vtpro_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
oceanic_vtpro_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{

View File

@ -42,6 +42,8 @@ struct dc_parser_t {
};
struct dc_parser_vtable_t {
size_t size;
dc_family_t type;
dc_status_t (*set_data) (dc_parser_t *parser, const unsigned char *data, unsigned int size);
@ -55,8 +57,11 @@ struct dc_parser_vtable_t {
dc_status_t (*destroy) (dc_parser_t *parser);
};
dc_parser_t *
dc_parser_allocate (dc_context_t *context, const dc_parser_vtable_t *vtable);
void
parser_init (dc_parser_t *parser, dc_context_t *context, const dc_parser_vtable_t *vtable);
dc_parser_deallocate (dc_parser_t *parser);
int
dc_parser_isinstance (dc_parser_t *parser, const dc_parser_vtable_t *vtable);

View File

@ -20,6 +20,7 @@
*/
#include <stdlib.h>
#include <assert.h>
#include <libdivecomputer/suunto.h>
#include <libdivecomputer/reefnet.h>
@ -35,6 +36,7 @@
#include <libdivecomputer/citizen.h>
#include <libdivecomputer/divesystem.h>
#include "context-private.h"
#include "parser-private.h"
#include "device-private.h"
@ -140,7 +142,7 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device)
rc = citizen_aqualand_parser_create (&parser, context);
break;
case DC_FAMILY_DIVESYSTEM_IDIVE:
rc = divesystem_idive_parser_create (&parser, context);
rc = divesystem_idive_parser_create2 (&parser, context, device->devinfo.model);
break;
default:
return DC_STATUS_INVALIDARGS;
@ -152,15 +154,35 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device)
}
void
parser_init (dc_parser_t *parser, dc_context_t *context, const dc_parser_vtable_t *vtable)
dc_parser_t *
dc_parser_allocate (dc_context_t *context, const dc_parser_vtable_t *vtable)
{
dc_parser_t *parser = NULL;
assert(vtable != NULL);
assert(vtable->size >= sizeof(dc_parser_t));
// Allocate memory.
parser = (dc_parser_t *) malloc (vtable->size);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return parser;
}
// Initialize the base class.
parser->vtable = vtable;
parser->context = context;
parser->data = NULL;
parser->size = 0;
return parser;
}
void
dc_parser_deallocate (dc_parser_t *parser)
{
free (parser);
}
int
dc_parser_isinstance (dc_parser_t *parser, const dc_parser_vtable_t *vtable)
@ -239,13 +261,18 @@ dc_parser_samples_foreach (dc_parser_t *parser, dc_sample_callback_t callback, v
dc_status_t
dc_parser_destroy (dc_parser_t *parser)
{
dc_status_t status = DC_STATUS_SUCCESS;
if (parser == NULL)
return DC_STATUS_SUCCESS;
if (parser->vtable->destroy == NULL)
return DC_STATUS_UNSUPPORTED;
if (parser->vtable->destroy) {
status = parser->vtable->destroy (parser);
}
return parser->vtable->destroy (parser);
dc_parser_deallocate (parser);
return status;
}

View File

@ -56,6 +56,7 @@ static dc_status_t reefnet_sensus_device_foreach (dc_device_t *abstract, dc_dive
static dc_status_t reefnet_sensus_device_close (dc_device_t *abstract);
static const dc_device_vtable_t reefnet_sensus_device_vtable = {
sizeof(reefnet_sensus_device_t),
DC_FAMILY_REEFNET_SENSUS,
reefnet_sensus_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -89,19 +90,19 @@ reefnet_sensus_cancel (reefnet_sensus_device_t *device)
dc_status_t
reefnet_sensus_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
reefnet_sensus_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
reefnet_sensus_device_t *device = (reefnet_sensus_device_t *) malloc (sizeof (reefnet_sensus_device_t));
device = (reefnet_sensus_device_t *) dc_device_allocate (context, &reefnet_sensus_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &reefnet_sensus_device_vtable);
// Set the default values.
device->port = NULL;
device->waiting = 0;
@ -114,25 +115,23 @@ reefnet_sensus_device_open (dc_device_t **out, dc_context_t *context, const char
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (19200 8N1).
rc = serial_configure (device->port, 19200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (3000 ms).
if (serial_set_timeout (device->port, 3000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -141,12 +140,19 @@ reefnet_sensus_device_open (dc_device_t **out, dc_context_t *context, const char
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
reefnet_sensus_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
reefnet_sensus_device_t *device = (reefnet_sensus_device_t*) abstract;
// Safely close the connection if the last handshake was
@ -156,14 +162,10 @@ reefnet_sensus_device_close (dc_device_t *abstract)
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -52,34 +52,33 @@ static dc_status_t reefnet_sensus_parser_set_data (dc_parser_t *abstract, const
static dc_status_t reefnet_sensus_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t reefnet_sensus_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t reefnet_sensus_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t reefnet_sensus_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t reefnet_sensus_parser_vtable = {
sizeof(reefnet_sensus_parser_t),
DC_FAMILY_REEFNET_SENSUS,
reefnet_sensus_parser_set_data, /* set_data */
reefnet_sensus_parser_get_datetime, /* datetime */
reefnet_sensus_parser_get_field, /* fields */
reefnet_sensus_parser_samples_foreach, /* samples_foreach */
reefnet_sensus_parser_destroy /* destroy */
NULL /* destroy */
};
dc_status_t
reefnet_sensus_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int devtime, dc_ticks_t systime)
{
reefnet_sensus_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
reefnet_sensus_parser_t *parser = (reefnet_sensus_parser_t *) malloc (sizeof (reefnet_sensus_parser_t));
parser = (reefnet_sensus_parser_t *) dc_parser_allocate (context, &reefnet_sensus_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &reefnet_sensus_parser_vtable);
// Set the default values.
parser->atmospheric = ATM;
parser->hydrostatic = 1025.0 * GRAVITY;
@ -95,16 +94,6 @@ reefnet_sensus_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
}
static dc_status_t
reefnet_sensus_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
reefnet_sensus_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{

View File

@ -55,6 +55,7 @@ static dc_status_t reefnet_sensuspro_device_foreach (dc_device_t *abstract, dc_d
static dc_status_t reefnet_sensuspro_device_close (dc_device_t *abstract);
static const dc_device_vtable_t reefnet_sensuspro_device_vtable = {
sizeof(reefnet_sensuspro_device_t),
DC_FAMILY_REEFNET_SENSUSPRO,
reefnet_sensuspro_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -68,19 +69,19 @@ static const dc_device_vtable_t reefnet_sensuspro_device_vtable = {
dc_status_t
reefnet_sensuspro_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
reefnet_sensuspro_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
reefnet_sensuspro_device_t *device = (reefnet_sensuspro_device_t *) malloc (sizeof (reefnet_sensuspro_device_t));
device = (reefnet_sensuspro_device_t *) dc_device_allocate (context, &reefnet_sensuspro_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &reefnet_sensuspro_device_vtable);
// Set the default values.
device->port = NULL;
device->timestamp = 0;
@ -92,25 +93,23 @@ reefnet_sensuspro_device_open (dc_device_t **out, dc_context_t *context, const c
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (19200 8N1).
rc = serial_configure (device->port, 19200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (3000ms).
if (serial_set_timeout (device->port, 3000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -119,24 +118,27 @@ reefnet_sensuspro_device_open (dc_device_t **out, dc_context_t *context, const c
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
reefnet_sensuspro_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
reefnet_sensuspro_device_t *device = (reefnet_sensuspro_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -51,34 +51,33 @@ static dc_status_t reefnet_sensuspro_parser_set_data (dc_parser_t *abstract, con
static dc_status_t reefnet_sensuspro_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t reefnet_sensuspro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t reefnet_sensuspro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t reefnet_sensuspro_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t reefnet_sensuspro_parser_vtable = {
sizeof(reefnet_sensuspro_parser_t),
DC_FAMILY_REEFNET_SENSUSPRO,
reefnet_sensuspro_parser_set_data, /* set_data */
reefnet_sensuspro_parser_get_datetime, /* datetime */
reefnet_sensuspro_parser_get_field, /* fields */
reefnet_sensuspro_parser_samples_foreach, /* samples_foreach */
reefnet_sensuspro_parser_destroy /* destroy */
NULL /* destroy */
};
dc_status_t
reefnet_sensuspro_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int devtime, dc_ticks_t systime)
{
reefnet_sensuspro_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
reefnet_sensuspro_parser_t *parser = (reefnet_sensuspro_parser_t *) malloc (sizeof (reefnet_sensuspro_parser_t));
parser = (reefnet_sensuspro_parser_t *) dc_parser_allocate (context, &reefnet_sensuspro_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &reefnet_sensuspro_parser_vtable);
// Set the default values.
parser->atmospheric = ATM;
parser->hydrostatic = 1025.0 * GRAVITY;
@ -94,16 +93,6 @@ reefnet_sensuspro_parser_create (dc_parser_t **out, dc_context_t *context, unsig
}
static dc_status_t
reefnet_sensuspro_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
reefnet_sensuspro_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{

View File

@ -64,6 +64,7 @@ static dc_status_t reefnet_sensusultra_device_foreach (dc_device_t *abstract, dc
static dc_status_t reefnet_sensusultra_device_close (dc_device_t *abstract);
static const dc_device_vtable_t reefnet_sensusultra_device_vtable = {
sizeof(reefnet_sensusultra_device_t),
DC_FAMILY_REEFNET_SENSUSULTRA,
reefnet_sensusultra_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -77,19 +78,19 @@ static const dc_device_vtable_t reefnet_sensusultra_device_vtable = {
dc_status_t
reefnet_sensusultra_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
reefnet_sensusultra_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
reefnet_sensusultra_device_t *device = (reefnet_sensusultra_device_t *) malloc (sizeof (reefnet_sensusultra_device_t));
device = (reefnet_sensusultra_device_t *) dc_device_allocate (context, &reefnet_sensusultra_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &reefnet_sensusultra_device_vtable);
// Set the default values.
device->port = NULL;
device->timestamp = 0;
@ -101,25 +102,23 @@ reefnet_sensusultra_device_open (dc_device_t **out, dc_context_t *context, const
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (115200 8N1).
rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (3000ms).
if (serial_set_timeout (device->port, 3000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -128,24 +127,27 @@ reefnet_sensusultra_device_open (dc_device_t **out, dc_context_t *context, const
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
reefnet_sensusultra_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
reefnet_sensusultra_device_t *device = (reefnet_sensusultra_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -51,34 +51,33 @@ static dc_status_t reefnet_sensusultra_parser_set_data (dc_parser_t *abstract, c
static dc_status_t reefnet_sensusultra_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t reefnet_sensusultra_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t reefnet_sensusultra_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t reefnet_sensusultra_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t reefnet_sensusultra_parser_vtable = {
sizeof(reefnet_sensusultra_parser_t),
DC_FAMILY_REEFNET_SENSUSULTRA,
reefnet_sensusultra_parser_set_data, /* set_data */
reefnet_sensusultra_parser_get_datetime, /* datetime */
reefnet_sensusultra_parser_get_field, /* fields */
reefnet_sensusultra_parser_samples_foreach, /* samples_foreach */
reefnet_sensusultra_parser_destroy /* destroy */
NULL /* destroy */
};
dc_status_t
reefnet_sensusultra_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int devtime, dc_ticks_t systime)
{
reefnet_sensusultra_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
reefnet_sensusultra_parser_t *parser = (reefnet_sensusultra_parser_t *) malloc (sizeof (reefnet_sensusultra_parser_t));
parser = (reefnet_sensusultra_parser_t *) dc_parser_allocate (context, &reefnet_sensusultra_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &reefnet_sensusultra_parser_vtable);
// Set the default values.
parser->atmospheric = ATM;
parser->hydrostatic = 1025.0 * GRAVITY;
@ -94,16 +93,6 @@ reefnet_sensusultra_parser_create (dc_parser_t **out, dc_context_t *context, uns
}
static dc_status_t
reefnet_sensusultra_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
reefnet_sensusultra_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{

View File

@ -137,7 +137,7 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
// Allocate memory.
serial_t *device = (serial_t *) malloc (sizeof (serial_t));
if (device == NULL) {
SYSERROR (context, errno);
SYSERROR (context, ENOMEM);
return -1; // ENOMEM (Not enough space)
}
@ -157,17 +157,14 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
device->fd = open (name, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (device->fd == -1) {
SYSERROR (context, errno);
free (device);
return -1; // Error during open call.
goto error_free;
}
#ifndef ENABLE_PTY
// Enable exclusive access mode.
if (ioctl (device->fd, TIOCEXCL, NULL) != 0) {
SYSERROR (context, errno);
close (device->fd);
free (device);
return -1;
goto error_close;
}
#endif
@ -177,14 +174,18 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
// file descriptor represents a terminal device.
if (tcgetattr (device->fd, &device->tty) != 0) {
SYSERROR (context, errno);
close (device->fd);
free (device);
return -1;
goto error_close;
}
*out = device;
return 0;
error_close:
close (device->fd);
error_free:
free (device);
return -1;
}
//
@ -194,15 +195,15 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
int
serial_close (serial_t *device)
{
int errcode = 0;
if (device == NULL)
return 0;
// Restore the initial terminal attributes.
if (tcsetattr (device->fd, TCSANOW, &device->tty) != 0) {
SYSERROR (device->context, errno);
close (device->fd);
free (device);
return -1;
errcode = -1;
}
#ifndef ENABLE_PTY
@ -213,14 +214,13 @@ serial_close (serial_t *device)
// Close the device.
if (close (device->fd) != 0) {
SYSERROR (device->context, errno);
free (device);
return -1;
errcode = -1;
}
// Free memory.
free (device);
return 0;
return errcode;
}
//

View File

@ -150,8 +150,7 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
NULL);
if (device->hFile == INVALID_HANDLE_VALUE) {
SYSERROR (context, GetLastError ());
free (device);
return -1;
goto error_free;
}
// Retrieve the current communication settings and timeouts,
@ -161,14 +160,18 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
if (!GetCommState (device->hFile, &device->dcb) ||
!GetCommTimeouts (device->hFile, &device->timeouts)) {
SYSERROR (context, GetLastError ());
CloseHandle (device->hFile);
free (device);
return -1;
goto error_close;
}
*out = device;
return 0;
error_close:
CloseHandle (device->hFile);
error_free:
free (device);
return -1;
}
//
@ -178,6 +181,8 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
int
serial_close (serial_t *device)
{
int errcode = 0;
if (device == NULL)
return 0;
@ -185,22 +190,19 @@ serial_close (serial_t *device)
if (!SetCommState (device->hFile, &device->dcb) ||
!SetCommTimeouts (device->hFile, &device->timeouts)) {
SYSERROR (device->context, GetLastError ());
CloseHandle (device->hFile);
free (device);
return -1;
errcode = -1;
}
// Close the device.
if (!CloseHandle (device->hFile)) {
SYSERROR (device->context, GetLastError ());
free (device);
return -1;
errcode = -1;
}
// Free memory.
free (device);
return 0;
return errcode;
}
//

View File

@ -41,6 +41,8 @@
dc_status_t
shearwater_common_open (shearwater_common_device_t *device, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
// Open the device.
int rc = dc_serial_native_open (&device->serial, context, name);
if (rc != DC_STATUS_SUCCESS) {
@ -52,15 +54,15 @@ shearwater_common_open (shearwater_common_device_t *device, dc_context_t *contex
rc = serial_configure (device->serial->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
device->serial->ops->close (device->serial->port);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (3000ms).
if (serial_set_timeout (device->serial->port, 3000) == -1) {
ERROR (context, "Failed to set the timeout.");
device->serial->ops->close (device->serial->port);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -68,12 +70,18 @@ shearwater_common_open (shearwater_common_device_t *device, dc_context_t *contex
device->serial->ops->flush (device->serial->port, SERIAL_QUEUE_BOTH);
return DC_STATUS_SUCCESS;
error_close:
device->serial->ops->close (device->serial->port);
return status;
}
dc_status_t
shearwater_common_custom_open (shearwater_common_device_t *device, dc_context_t *context, dc_serial_t *serial)
{
dc_status_t status = DC_STATUS_SUCCESS;
// Set the serial reference
device->serial = serial;
@ -91,7 +99,8 @@ shearwater_common_custom_open (shearwater_common_device_t *device, dc_context_t
if (device->serial->ops->set_timeout (device->serial->port, 3000) == -1) {
ERROR (context, "Failed to set the timeout.");
device->serial->ops->close (device->serial->port);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -99,6 +108,10 @@ shearwater_common_custom_open (shearwater_common_device_t *device, dc_context_t
device->serial->ops->flush (device->serial->port, SERIAL_QUEUE_BOTH);
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->serial->port);
return status;
}

View File

@ -52,6 +52,7 @@ static dc_status_t shearwater_petrel_device_foreach (dc_device_t *abstract, dc_d
static dc_status_t shearwater_petrel_device_close (dc_device_t *abstract);
static const dc_device_vtable_t shearwater_petrel_device_vtable = {
sizeof(shearwater_petrel_device_t),
DC_FAMILY_SHEARWATER_PETREL,
shearwater_petrel_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -80,34 +81,35 @@ str2num (unsigned char data[], unsigned int size, unsigned int offset)
dc_status_t
shearwater_petrel_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t rc = DC_STATUS_SUCCESS;
dc_status_t status = DC_STATUS_SUCCESS;
shearwater_petrel_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
shearwater_petrel_device_t *device = (shearwater_petrel_device_t *) malloc (sizeof (shearwater_petrel_device_t));
device = (shearwater_petrel_device_t *) dc_device_allocate (context, &shearwater_petrel_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base.base, context, &shearwater_petrel_device_vtable);
// Set the default values.
memset (device->fingerprint, 0, sizeof (device->fingerprint));
// Open the device.
rc = shearwater_common_open (&device->base, context, name);
if (rc != DC_STATUS_SUCCESS) {
free (device);
return rc;
status = shearwater_common_open (&device->base, context, name);
if (status != DC_STATUS_SUCCESS) {
goto error_free;
}
*out = (dc_device_t *) device;
return DC_STATUS_SUCCESS;
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
@ -148,7 +150,6 @@ shearwater_petrel_device_custom_open (dc_device_t **out, dc_context_t *context,
static dc_status_t
shearwater_petrel_device_close (dc_device_t *abstract)
{
dc_status_t rc = DC_STATUS_SUCCESS;
shearwater_common_device_t *device = (shearwater_common_device_t *) abstract;
// Shutdown the device.
@ -156,12 +157,7 @@ shearwater_petrel_device_close (dc_device_t *abstract)
shearwater_common_transfer (device, request, sizeof (request), NULL, 0, NULL);
// Close the device.
rc = shearwater_common_close (device);
// Free memory.
free (device);
return rc;
return shearwater_common_close (device);
}

View File

@ -53,6 +53,7 @@ static dc_status_t shearwater_predator_device_foreach (dc_device_t *abstract, dc
static dc_status_t shearwater_predator_device_close (dc_device_t *abstract);
static const dc_device_vtable_t shearwater_predator_device_vtable = {
sizeof(shearwater_predator_device_t),
DC_FAMILY_SHEARWATER_PREDATOR,
shearwater_predator_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -66,34 +67,35 @@ static const dc_device_vtable_t shearwater_predator_device_vtable = {
dc_status_t
shearwater_predator_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t rc = DC_STATUS_SUCCESS;
dc_status_t status = DC_STATUS_SUCCESS;
shearwater_predator_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
shearwater_predator_device_t *device = (shearwater_predator_device_t *) malloc (sizeof (shearwater_predator_device_t));
device = (shearwater_predator_device_t *) dc_device_allocate (context, &shearwater_predator_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base.base, context, &shearwater_predator_device_vtable);
// Set the default values.
memset (device->fingerprint, 0, sizeof (device->fingerprint));
// Open the device.
rc = shearwater_common_open (&device->base, context, name);
if (rc != DC_STATUS_SUCCESS) {
free (device);
return rc;
status = shearwater_common_open (&device->base, context, name);
if (status != DC_STATUS_SUCCESS) {
goto error_free;
}
*out = (dc_device_t *) device;
return DC_STATUS_SUCCESS;
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
@ -134,16 +136,9 @@ shearwater_predator_device_custom_open (dc_device_t **out, dc_context_t *context
static dc_status_t
shearwater_predator_device_close (dc_device_t *abstract)
{
dc_status_t rc = DC_STATUS_SUCCESS;
shearwater_common_device_t *device = (shearwater_common_device_t *) abstract;
// Close the device.
rc = shearwater_common_close (device);
// Free memory.
free (device);
return rc;
return shearwater_common_close (device);
}

View File

@ -74,35 +74,62 @@ static dc_status_t shearwater_predator_parser_set_data (dc_parser_t *abstract, c
static dc_status_t shearwater_predator_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t shearwater_predator_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t shearwater_predator_parser_vtable = {
sizeof(shearwater_predator_parser_t),
DC_FAMILY_SHEARWATER_PREDATOR,
shearwater_predator_parser_set_data, /* set_data */
shearwater_predator_parser_get_datetime, /* datetime */
shearwater_predator_parser_get_field, /* fields */
shearwater_predator_parser_samples_foreach, /* samples_foreach */
shearwater_predator_parser_destroy /* destroy */
NULL /* destroy */
};
static const dc_parser_vtable_t shearwater_petrel_parser_vtable = {
sizeof(shearwater_predator_parser_t),
DC_FAMILY_SHEARWATER_PETREL,
shearwater_predator_parser_set_data, /* set_data */
shearwater_predator_parser_get_datetime, /* datetime */
shearwater_predator_parser_get_field, /* fields */
shearwater_predator_parser_samples_foreach, /* samples_foreach */
shearwater_predator_parser_destroy /* destroy */
NULL /* destroy */
};
static unsigned int
shearwater_predator_find_gasmix (shearwater_predator_parser_t *parser, unsigned int o2, unsigned int he)
{
unsigned int i = 0;
while (i < parser->ngasmixes) {
if (o2 == parser->oxygen[i] && he == parser->helium[i])
break;
i++;
}
return i;
}
dc_status_t
shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int petrel)
{
shearwater_predator_parser_t *parser = NULL;
const dc_parser_vtable_t *vtable = NULL;
unsigned int samplesize = 0;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
if (petrel) {
vtable = &shearwater_petrel_parser_vtable;
samplesize = SZ_SAMPLE_PETREL;
} else {
vtable = &shearwater_predator_parser_vtable;
samplesize = SZ_SAMPLE_PREDATOR;
}
// Allocate memory.
shearwater_predator_parser_t *parser = (shearwater_predator_parser_t *) malloc (sizeof (shearwater_predator_parser_t));
parser = (shearwater_predator_parser_t *) dc_parser_allocate (context, vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
@ -149,16 +176,6 @@ shearwater_petrel_parser_create (dc_parser_t **out, dc_context_t *context, unsig
}
static dc_status_t
shearwater_predator_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
shearwater_predator_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
@ -443,7 +460,14 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Temperature (°C or °F).
unsigned int temperature = data[offset + 13];
int temperature = (signed char) data[offset + 13];
if (temperature < 0) {
// Fix negative temperatures.
temperature += 102;
if (temperature > 0) {
temperature = 0;
}
}
if (units == IMPERIAL)
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
else
@ -481,11 +505,21 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal
unsigned int o2 = data[offset + 7];
unsigned int he = data[offset + 8];
if (o2 != o2_previous || he != he_previous) {
unsigned int idx = shearwater_predator_find_gasmix (parser, o2, he);
if (idx >= parser->ngasmixes) {
ERROR (abstract->context, "Invalid gas mix.");
return DC_STATUS_DATAFORMAT;
}
sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
sample.event.type = SAMPLE_EVENT_GASCHANGE2;
sample.event.time = 0;
sample.event.flags = 0;
sample.event.value = o2 | (he << 16);
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
#endif
o2_previous = o2;
he_previous = he;
}

View File

@ -31,13 +31,10 @@
#define RB_PROFILE_PEEK(a,l) ringbuffer_decrement (a, l->peek, l->rb_profile_begin, l->rb_profile_end)
void
suunto_common_device_init (suunto_common_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable)
suunto_common_device_init (suunto_common_device_t *device)
{
assert (device != NULL);
// Initialize the base class.
device_init (&device->base, context, vtable);
// Set the default values.
memset (device->fingerprint, 0, sizeof (device->fingerprint));
}

View File

@ -46,7 +46,7 @@ typedef struct suunto_common_layout_t {
} suunto_common_layout_t;
void
suunto_common_device_init (suunto_common_device_t *device, dc_context_t *context, const dc_device_vtable_t *vtable);
suunto_common_device_init (suunto_common_device_t *device);
dc_status_t
suunto_common_device_set_fingerprint (dc_device_t *device, const unsigned char data[], unsigned int size);

View File

@ -40,13 +40,10 @@
#define VTABLE(abstract) ((suunto_common2_device_vtable_t *) abstract->vtable)
void
suunto_common2_device_init (suunto_common2_device_t *device, dc_context_t *context, const suunto_common2_device_vtable_t *vtable)
suunto_common2_device_init (suunto_common2_device_t *device)
{
assert (device != NULL);
// Initialize the base class.
device_init (&device->base, context, &vtable->base);
// Set the default values.
device->layout = NULL;
memset (device->version, 0, sizeof (device->version));

View File

@ -53,7 +53,7 @@ typedef struct suunto_common2_device_vtable_t {
} suunto_common2_device_vtable_t;
void
suunto_common2_device_init (suunto_common2_device_t *device, dc_context_t *context, const suunto_common2_device_vtable_t *vtable);
suunto_common2_device_init (suunto_common2_device_t *device);
dc_status_t
suunto_common2_device_set_fingerprint (dc_device_t *device, const unsigned char data[], unsigned int size);

View File

@ -55,6 +55,7 @@ static dc_status_t suunto_d9_device_close (dc_device_t *abstract);
static const suunto_common2_device_vtable_t suunto_d9_device_vtable = {
{
sizeof(suunto_d9_device_t),
DC_FAMILY_SUUNTO_D9,
suunto_common2_device_set_fingerprint, /* set_fingerprint */
suunto_common2_device_read, /* read */
@ -129,18 +130,21 @@ suunto_d9_device_autodetect (suunto_d9_device_t *device, unsigned int model)
dc_status_t
suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model)
{
dc_status_t status = DC_STATUS_SUCCESS;
suunto_d9_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
suunto_d9_device_t *device = (suunto_d9_device_t *) malloc (sizeof (suunto_d9_device_t));
device = (suunto_d9_device_t *) dc_device_allocate (context, &suunto_d9_device_vtable.base);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
suunto_common2_device_init (&device->base, context, &suunto_d9_device_vtable);
suunto_common2_device_init (&device->base);
// Set the default values.
device->port = NULL;
@ -149,33 +153,30 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (3000 ms).
if (serial_set_timeout (device->port, 3000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the DTR line (power supply for the interface).
if (serial_set_dtr (device->port, 1) == -1) {
ERROR (context, "Failed to set the DTR line.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Give the interface 100 ms to settle and draw power up.
@ -185,12 +186,10 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam
serial_flush (device->port, SERIAL_QUEUE_BOTH);
// Try to autodetect the protocol variant.
dc_status_t status = suunto_d9_device_autodetect (device, model);
status = suunto_d9_device_autodetect (device, model);
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to identify the protocol variant.");
serial_close (device->port);
free (device);
return status;
goto error_close;
}
// Override the base class values.
@ -205,24 +204,27 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
suunto_d9_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
suunto_d9_device_t *device = (suunto_d9_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -85,17 +85,30 @@ static dc_status_t suunto_d9_parser_set_data (dc_parser_t *abstract, const unsig
static dc_status_t suunto_d9_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t suunto_d9_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t suunto_d9_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t suunto_d9_parser_vtable = {
sizeof(suunto_d9_parser_t),
DC_FAMILY_SUUNTO_D9,
suunto_d9_parser_set_data, /* set_data */
suunto_d9_parser_get_datetime, /* datetime */
suunto_d9_parser_get_field, /* fields */
suunto_d9_parser_samples_foreach, /* samples_foreach */
suunto_d9_parser_destroy /* destroy */
NULL /* destroy */
};
static unsigned int
suunto_d9_parser_find_gasmix (suunto_d9_parser_t *parser, unsigned int o2, unsigned int he)
{
// Find the gasmix in the list.
unsigned int i = 0;
while (i < parser->ngasmixes) {
if (o2 == parser->oxygen[i] && he == parser->helium[i])
break;
i++;
}
return i;
}
static dc_status_t
suunto_d9_parser_cache (suunto_d9_parser_t *parser)
@ -192,19 +205,18 @@ suunto_d9_parser_cache (suunto_d9_parser_t *parser)
dc_status_t
suunto_d9_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model, unsigned int serial)
{
suunto_d9_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
suunto_d9_parser_t *parser = (suunto_d9_parser_t *) malloc (sizeof (suunto_d9_parser_t));
parser = (suunto_d9_parser_t *) dc_parser_allocate (context, &suunto_d9_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &suunto_d9_parser_vtable);
// Set the default values.
parser->model = model;
parser->serial = serial;
@ -224,16 +236,6 @@ suunto_d9_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int
}
static dc_status_t
suunto_d9_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
suunto_d9_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
@ -505,12 +507,16 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca
ERROR (abstract->context, "Invalid initial gas mix.");
return DC_STATUS_DATAFORMAT;
}
sample.gasmix = parser->gasmix;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
unsigned int he = parser->helium[parser->gasmix];
unsigned int o2 = parser->oxygen[parser->gasmix];
sample.event.type = SAMPLE_EVENT_GASCHANGE2;
sample.event.time = 0;
sample.event.value = o2 | (he << 16);
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
#endif
}
// Events
@ -519,7 +525,7 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca
unsigned int event = data[offset++];
unsigned int seconds, type, unknown, heading;
unsigned int current, next;
unsigned int he, o2;
unsigned int he, o2, idx;
unsigned int length;
sample.event.type = SAMPLE_EVENT_NONE;
@ -686,10 +692,19 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca
}
o2 = data[offset + 0];
seconds = data[offset + 1];
idx = suunto_d9_parser_find_gasmix(parser, o2, 0);
if (idx >= parser->ngasmixes) {
ERROR (abstract->context, "Invalid gas mix.");
return DC_STATUS_DATAFORMAT;
}
sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
sample.event.type = SAMPLE_EVENT_GASCHANGE;
sample.event.time = seconds;
sample.event.value = o2;
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
#endif
offset += 2;
break;
case 0x06: // Gas Change
@ -709,10 +724,19 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca
} else {
seconds = data[offset + 3];
}
idx = suunto_d9_parser_find_gasmix(parser, o2, he);
if (idx >= parser->ngasmixes) {
ERROR (abstract->context, "Invalid gas mix.");
return DC_STATUS_DATAFORMAT;
}
sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
sample.event.type = SAMPLE_EVENT_GASCHANGE2;
sample.event.time = seconds;
sample.event.value = o2 | (he << 16);
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
#endif
offset += length;
break;
default:

View File

@ -50,6 +50,7 @@ static dc_status_t suunto_eon_device_foreach (dc_device_t *abstract, dc_dive_cal
static dc_status_t suunto_eon_device_close (dc_device_t *abstract);
static const dc_device_vtable_t suunto_eon_device_vtable = {
sizeof(suunto_eon_device_t),
DC_FAMILY_SUUNTO_EON,
suunto_common_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -71,18 +72,21 @@ static const suunto_common_layout_t suunto_eon_layout = {
dc_status_t
suunto_eon_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
suunto_eon_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
suunto_eon_device_t *device = (suunto_eon_device_t *) malloc (sizeof (suunto_eon_device_t));
device = (suunto_eon_device_t *) dc_device_allocate (context, &suunto_eon_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
suunto_common_device_init (&device->base, context, &suunto_eon_device_vtable);
suunto_common_device_init (&device->base);
// Set the default values.
device->port = NULL;
@ -91,56 +95,56 @@ suunto_eon_device_open (dc_device_t **out, dc_context_t *context, const char *na
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (1200 8N2).
rc = serial_configure (device->port, 1200, 8, SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (1000ms).
if (serial_set_timeout (device->port, 1000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Clear the RTS line.
if (serial_set_rts (device->port, 0)) {
ERROR (context, "Failed to set the DTR/RTS line.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
suunto_eon_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
suunto_eon_device_t *device = (suunto_eon_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -47,15 +47,15 @@ static dc_status_t suunto_eon_parser_set_data (dc_parser_t *abstract, const unsi
static dc_status_t suunto_eon_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t suunto_eon_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t suunto_eon_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t suunto_eon_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t suunto_eon_parser_vtable = {
sizeof(suunto_eon_parser_t),
DC_FAMILY_SUUNTO_EON,
suunto_eon_parser_set_data, /* set_data */
suunto_eon_parser_get_datetime, /* datetime */
suunto_eon_parser_get_field, /* fields */
suunto_eon_parser_samples_foreach, /* samples_foreach */
suunto_eon_parser_destroy /* destroy */
NULL /* destroy */
};
static dc_status_t
@ -111,19 +111,18 @@ suunto_eon_parser_cache (suunto_eon_parser_t *parser)
dc_status_t
suunto_eon_parser_create (dc_parser_t **out, dc_context_t *context, int spyder)
{
suunto_eon_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
suunto_eon_parser_t *parser = (suunto_eon_parser_t *) malloc (sizeof (suunto_eon_parser_t));
parser = (suunto_eon_parser_t *) dc_parser_allocate (context, &suunto_eon_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &suunto_eon_parser_vtable);
// Set the default values.
parser->spyder = spyder;
parser->cached = 0;
@ -138,16 +137,6 @@ suunto_eon_parser_create (dc_parser_t **out, dc_context_t *context, int spyder)
}
static dc_status_t
suunto_eon_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
suunto_eon_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{

View File

@ -40,7 +40,7 @@
#if __APPLE__ && HAVE_HIDAPI
#include "hidapi/hidapi.h"
#endif
#ifdef HAVE_LIBUSB
#if HAVE_LIBUSB || (__APPLE__ && HAVE_HIDAPI)
#ifdef _WIN32
#define NOGDI
@ -92,6 +92,7 @@ static dc_status_t suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive
static dc_status_t suunto_eonsteel_device_close(dc_device_t *abstract);
static const dc_device_vtable_t suunto_eonsteel_device_vtable = {
sizeof(suunto_eonsteel_device_t),
DC_FAMILY_SUUNTO_EONSTEEL,
NULL, /* set_fingerprint */
NULL, /* read */
@ -579,12 +580,13 @@ static int initialize_eonsteel(suunto_eonsteel_device_t *eon)
dc_status_t
suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, const char *name, unsigned int model)
{
suunto_eonsteel_device_t *eon;
dc_status_t status = DC_STATUS_SUCCESS;
suunto_eonsteel_device_t *eon = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
eon = (suunto_eonsteel_device_t *) calloc(1, sizeof(suunto_eonsteel_device_t));
eon = (suunto_eonsteel_device_t *) dc_device_allocate(context, &suunto_eonsteel_device_vtable);
if (!eon)
return DC_STATUS_NOMEMORY;
@ -592,39 +594,35 @@ suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, const char
eon->magic = INIT_MAGIC;
eon->seq = INIT_SEQ;
// Set up the libdivecomputer interfaces
device_init(&eon->base, context, &suunto_eonsteel_device_vtable);
#if __APPLE__ && HAVE_HIDAPI
if (hid_init()) {
ERROR(context, "hid_init() failed");
free(eon);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
eon->handle = hid_open(0x1493, 0x0030, NULL);
if (!eon->handle) {
ERROR(context, "unable to open device");
hid_exit();
free(eon);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_usb_exit;
}
#else
if (libusb_init(&eon->ctx)) {
ERROR(context, "libusb_init() failed");
free(eon);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
eon->handle = libusb_open_device_with_vid_pid(eon->ctx, 0x1493, 0x0030);
if (!eon->handle) {
ERROR(context, "unable to open device");
libusb_exit(eon->ctx);
free(eon);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_usb_exit;
}
#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000102)
@ -635,20 +633,31 @@ suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, const char
#endif
if (initialize_eonsteel(eon) < 0) {
ERROR(context, "unable to initialize device");
#if __APPLE__ && HAVE_HIDAPI
hid_close(eon->handle);
hid_exit();
#else
libusb_close(eon->handle);
libusb_exit(eon->ctx);
#endif
free(eon);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_usb_close;
}
*out = (dc_device_t *) eon;
return DC_STATUS_SUCCESS;
error_usb_close:
#if __APPLE__ && HAVE_HIDAPI
hid_close(eon->handle);
#else
libusb_close(eon->handle);
#endif
error_usb_exit:
#if __APPLE__ && HAVE_HIDAPI
hid_exit();
#else
libusb_exit(eon->ctx);
#endif
error_free:
free(eon);
return status;
}
static int count_dir_entries(struct directory_entry *de)

View File

@ -567,20 +567,23 @@ static void sample_gas_switch_event(struct sample_data *info, unsigned short idx
{
suunto_eonsteel_parser_t *eon = info->eon;
dc_sample_value_t sample = {0};
int o2, he;
if (idx < 1 || idx > eon->cache.ngases)
return;
// Horrible, broken, gas change events
o2 = 100 * eon->cache.gasmix[idx-1].oxygen;
he = 100 * eon->cache.gasmix[idx-1].helium;
sample.gasmix = idx - 1;
if (info->callback) info->callback(DC_SAMPLE_GASMIX, sample, info->userdata);
#ifdef ENABLE_DEPRECATED
unsigned int o2 = 100 * eon->cache.gasmix[idx-1].oxygen;
unsigned int he = 100 * eon->cache.gasmix[idx-1].helium;
sample.event.type = SAMPLE_EVENT_GASCHANGE2;
sample.event.value = o2 | (he << 16);
sample.event.time = 0;
sample.event.flags = idx;
sample.event.value = o2 | (he << 16);
if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata);
#endif
}
/*
@ -1300,11 +1303,12 @@ suunto_eonsteel_parser_destroy(dc_parser_t *parser)
suunto_eonsteel_parser_t *eon = (suunto_eonsteel_parser_t *) parser;
desc_free(eon->type_desc, MAXTYPE);
free(parser);
return DC_STATUS_SUCCESS;
}
static const dc_parser_vtable_t suunto_eonsteel_parser_vtable = {
sizeof(suunto_eonsteel_parser_t),
DC_FAMILY_SUUNTO_EONSTEEL,
suunto_eonsteel_parser_set_data, /* set_data */
suunto_eonsteel_parser_get_datetime, /* datetime */
@ -1316,18 +1320,21 @@ static const dc_parser_vtable_t suunto_eonsteel_parser_vtable = {
dc_status_t
suunto_eonsteel_parser_create(dc_parser_t **out, dc_context_t *context, unsigned int model)
{
suunto_eonsteel_parser_t *eon;
suunto_eonsteel_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
eon = (suunto_eonsteel_parser_t *) calloc(1, sizeof(*eon));
if (!eon)
parser = (suunto_eonsteel_parser_t *) dc_parser_allocate (context, &suunto_eonsteel_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
parser_init(&eon->base, context, &suunto_eonsteel_parser_vtable);
memset(&parser->type_desc, 0, sizeof(parser->type_desc));
memset(&parser->cache, 0, sizeof(parser->cache));
*out = (dc_parser_t *) eon;
*out = (dc_parser_t *) parser;
return DC_STATUS_SUCCESS;
}

View File

@ -52,6 +52,7 @@ static dc_status_t suunto_solution_device_foreach (dc_device_t *abstract, dc_div
static dc_status_t suunto_solution_device_close (dc_device_t *abstract);
static const dc_device_vtable_t suunto_solution_device_vtable = {
sizeof(suunto_solution_device_t),
DC_FAMILY_SUUNTO_SOLUTION,
NULL, /* set_fingerprint */
NULL, /* read */
@ -65,19 +66,19 @@ static const dc_device_vtable_t suunto_solution_device_vtable = {
dc_status_t
suunto_solution_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
suunto_solution_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
suunto_solution_device_t *device = (suunto_solution_device_t *) malloc (sizeof (suunto_solution_device_t));
device = (suunto_solution_device_t *) dc_device_allocate (context, &suunto_solution_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &suunto_solution_device_vtable);
// Set the default values.
device->port = NULL;
@ -85,56 +86,56 @@ suunto_solution_device_open (dc_device_t **out, dc_context_t *context, const cha
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (1200 8N2).
rc = serial_configure (device->port, 1200, 8, SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (1000ms).
if (serial_set_timeout (device->port, 1000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Clear the RTS line.
if (serial_set_rts (device->port, 0)) {
ERROR (context, "Failed to set the DTR/RTS line.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
suunto_solution_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
suunto_solution_device_t *device = (suunto_solution_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -42,34 +42,33 @@ struct suunto_solution_parser_t {
static dc_status_t suunto_solution_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
static dc_status_t suunto_solution_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t suunto_solution_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t suunto_solution_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t suunto_solution_parser_vtable = {
sizeof(suunto_solution_parser_t),
DC_FAMILY_SUUNTO_SOLUTION,
suunto_solution_parser_set_data, /* set_data */
NULL, /* datetime */
suunto_solution_parser_get_field, /* fields */
suunto_solution_parser_samples_foreach, /* samples_foreach */
suunto_solution_parser_destroy /* destroy */
NULL /* destroy */
};
dc_status_t
suunto_solution_parser_create (dc_parser_t **out, dc_context_t *context)
{
suunto_solution_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
suunto_solution_parser_t *parser = (suunto_solution_parser_t *) malloc (sizeof (suunto_solution_parser_t));
parser = (suunto_solution_parser_t *) dc_parser_allocate (context, &suunto_solution_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &suunto_solution_parser_vtable);
// Set the default values.
parser->cached = 0;
parser->divetime = 0;
@ -81,16 +80,6 @@ suunto_solution_parser_create (dc_parser_t **out, dc_context_t *context)
}
static dc_status_t
suunto_solution_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
suunto_solution_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{

View File

@ -62,6 +62,7 @@ static dc_status_t suunto_vyper_device_foreach (dc_device_t *abstract, dc_dive_c
static dc_status_t suunto_vyper_device_close (dc_device_t *abstract);
static const dc_device_vtable_t suunto_vyper_device_vtable = {
sizeof(suunto_vyper_device_t),
DC_FAMILY_SUUNTO_VYPER,
suunto_common_device_set_fingerprint, /* set_fingerprint */
suunto_vyper_device_read, /* read */
@ -91,18 +92,21 @@ static const suunto_common_layout_t suunto_spyder_layout = {
dc_status_t
suunto_vyper_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
suunto_vyper_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
suunto_vyper_device_t *device = (suunto_vyper_device_t *) malloc (sizeof (suunto_vyper_device_t));
device = (suunto_vyper_device_t *) dc_device_allocate (context, &suunto_vyper_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
suunto_common_device_init (&device->base, context, &suunto_vyper_device_vtable);
suunto_common_device_init (&device->base);
// Set the default values.
device->port = NULL;
@ -111,33 +115,30 @@ suunto_vyper_device_open (dc_device_t **out, dc_context_t *context, const char *
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status= DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (2400 8O1).
rc = serial_configure (device->port, 2400, 8, SERIAL_PARITY_ODD, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->port, 1000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the DTR line (power supply for the interface).
if (serial_set_dtr (device->port, 1) == -1) {
ERROR (context, "Failed to set the DTR line.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Give the interface 100 ms to settle and draw power up.
@ -149,24 +150,27 @@ suunto_vyper_device_open (dc_device_t **out, dc_context_t *context, const char *
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
suunto_vyper_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
suunto_vyper_device_t *device = (suunto_vyper_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -49,6 +49,7 @@ static dc_status_t suunto_vyper2_device_close (dc_device_t *abstract);
static const suunto_common2_device_vtable_t suunto_vyper2_device_vtable = {
{
sizeof(suunto_vyper2_device_t),
DC_FAMILY_SUUNTO_VYPER2,
suunto_common2_device_set_fingerprint, /* set_fingerprint */
suunto_common2_device_read, /* read */
@ -80,18 +81,21 @@ static const suunto_common2_layout_t suunto_helo2_layout = {
dc_status_t
suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
suunto_vyper2_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
suunto_vyper2_device_t *device = (suunto_vyper2_device_t *) malloc (sizeof (suunto_vyper2_device_t));
device = (suunto_vyper2_device_t *) dc_device_allocate (context, &suunto_vyper2_device_vtable.base);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
suunto_common2_device_init (&device->base, context, &suunto_vyper2_device_vtable);
suunto_common2_device_init (&device->base);
// Set the default values.
device->port = NULL;
@ -100,33 +104,30 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (3000 ms).
if (serial_set_timeout (device->port, 3000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the DTR line (power supply for the interface).
if (serial_set_dtr (device->port, 1) == -1) {
ERROR (context, "Failed to set the DTR line.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Give the interface 100 ms to settle and draw power up.
@ -139,12 +140,10 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char
serial_set_halfduplex (device->port, 1);
// Read the version info.
dc_status_t status = suunto_common2_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version));
status = suunto_common2_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version));
if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to read the version info.");
serial_close (device->port);
free (device);
return status;
goto error_close;
}
// Override the base class values.
@ -157,24 +156,27 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
suunto_vyper2_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
suunto_vyper2_device_t *device = (suunto_vyper2_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -48,17 +48,29 @@ static dc_status_t suunto_vyper_parser_set_data (dc_parser_t *abstract, const un
static dc_status_t suunto_vyper_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t suunto_vyper_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t suunto_vyper_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t suunto_vyper_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t suunto_vyper_parser_vtable = {
sizeof(suunto_vyper_parser_t),
DC_FAMILY_SUUNTO_VYPER,
suunto_vyper_parser_set_data, /* set_data */
suunto_vyper_parser_get_datetime, /* datetime */
suunto_vyper_parser_get_field, /* fields */
suunto_vyper_parser_samples_foreach, /* samples_foreach */
suunto_vyper_parser_destroy /* destroy */
NULL /* destroy */
};
static unsigned int
suunto_vyper_parser_find_gasmix (suunto_vyper_parser_t *parser, unsigned int o2)
{
unsigned int i = 0;
while (i < parser->ngasmixes) {
if (o2 == parser->oxygen[i])
break;
i++;
}
return i;
}
static dc_status_t
suunto_vyper_parser_cache (suunto_vyper_parser_t *parser)
@ -149,19 +161,18 @@ suunto_vyper_parser_cache (suunto_vyper_parser_t *parser)
dc_status_t
suunto_vyper_parser_create (dc_parser_t **out, dc_context_t *context)
{
suunto_vyper_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
suunto_vyper_parser_t *parser = (suunto_vyper_parser_t *) malloc (sizeof (suunto_vyper_parser_t));
parser = (suunto_vyper_parser_t *) dc_parser_allocate (context, &suunto_vyper_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &suunto_vyper_parser_vtable);
// Set the default values.
parser->cached = 0;
parser->divetime = 0;
@ -178,16 +189,6 @@ suunto_vyper_parser_create (dc_parser_t **out, dc_context_t *context)
}
static dc_status_t
suunto_vyper_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
suunto_vyper_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
@ -353,6 +354,7 @@ suunto_vyper_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
complete = 1;
} else {
// Event.
unsigned int o2 = 0, idx = 0;
sample.event.type = SAMPLE_EVENT_NONE;
sample.event.time = 0;
sample.event.flags = 0;
@ -382,8 +384,22 @@ suunto_vyper_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
case 0x87: // Gas Change
if (offset + 1 > size)
return DC_STATUS_DATAFORMAT;
o2 = data[offset++];
idx = suunto_vyper_parser_find_gasmix (parser, o2);
if (idx >= parser->ngasmixes) {
ERROR (abstract->context, "Maximum number of gas mixes reached.");
return DC_STATUS_DATAFORMAT;
}
sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
#ifdef ENABLE_DEPRECATED
sample.event.type = SAMPLE_EVENT_GASCHANGE;
sample.event.value = data[offset++];
sample.event.value = o2;
#else
sample.event.type = SAMPLE_EVENT_NONE;
#endif
break;
default: // Unknown
WARNING (abstract->context, "Unknown event");

View File

@ -61,6 +61,7 @@ static dc_status_t uwatec_aladin_device_foreach (dc_device_t *abstract, dc_dive_
static dc_status_t uwatec_aladin_device_close (dc_device_t *abstract);
static const dc_device_vtable_t uwatec_aladin_device_vtable = {
sizeof(uwatec_aladin_device_t),
DC_FAMILY_UWATEC_ALADIN,
uwatec_aladin_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -74,19 +75,19 @@ static const dc_device_vtable_t uwatec_aladin_device_vtable = {
dc_status_t
uwatec_aladin_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
uwatec_aladin_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
uwatec_aladin_device_t *device = (uwatec_aladin_device_t *) malloc (sizeof (uwatec_aladin_device_t));
device = (uwatec_aladin_device_t *) dc_device_allocate (context, &uwatec_aladin_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &uwatec_aladin_device_vtable);
// Set the default values.
device->port = NULL;
device->timestamp = 0;
@ -97,57 +98,57 @@ uwatec_aladin_device_open (dc_device_t **out, dc_context_t *context, const char
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (19200 8N1).
rc = serial_configure (device->port, 19200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (INFINITE).
if (serial_set_timeout (device->port, -1) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Clear the RTS line and set the DTR line.
if (serial_set_dtr (device->port, 1) == -1 ||
serial_set_rts (device->port, 0) == -1) {
ERROR (context, "Failed to set the DTR/RTS line.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
uwatec_aladin_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
uwatec_aladin_device_t *device = (uwatec_aladin_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -57,6 +57,7 @@ static dc_status_t uwatec_memomouse_device_foreach (dc_device_t *abstract, dc_di
static dc_status_t uwatec_memomouse_device_close (dc_device_t *abstract);
static const dc_device_vtable_t uwatec_memomouse_device_vtable = {
sizeof(uwatec_memomouse_device_t),
DC_FAMILY_UWATEC_MEMOMOUSE,
uwatec_memomouse_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -70,19 +71,19 @@ static const dc_device_vtable_t uwatec_memomouse_device_vtable = {
dc_status_t
uwatec_memomouse_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
uwatec_memomouse_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
uwatec_memomouse_device_t *device = (uwatec_memomouse_device_t *) malloc (sizeof (uwatec_memomouse_device_t));
device = (uwatec_memomouse_device_t *) dc_device_allocate (context, &uwatec_memomouse_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &uwatec_memomouse_device_vtable);
// Set the default values.
device->port = NULL;
device->timestamp = 0;
@ -93,34 +94,31 @@ uwatec_memomouse_device_open (dc_device_t **out, dc_context_t *context, const ch
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (9600 8N1).
rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (1000 ms).
if (serial_set_timeout (device->port, 1000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Clear the RTS and DTR lines.
if (serial_set_rts (device->port, 0) == -1 ||
serial_set_dtr (device->port, 0) == -1) {
ERROR (context, "Failed to set the DTR/RTS line.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -129,24 +127,27 @@ uwatec_memomouse_device_open (dc_device_t **out, dc_context_t *context, const ch
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
uwatec_memomouse_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
uwatec_memomouse_device_t *device = (uwatec_memomouse_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

View File

@ -42,34 +42,33 @@ static dc_status_t uwatec_memomouse_parser_set_data (dc_parser_t *abstract, cons
static dc_status_t uwatec_memomouse_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t uwatec_memomouse_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t uwatec_memomouse_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t uwatec_memomouse_parser_destroy (dc_parser_t *abstract);
static const dc_parser_vtable_t uwatec_memomouse_parser_vtable = {
sizeof(uwatec_memomouse_parser_t),
DC_FAMILY_UWATEC_MEMOMOUSE,
uwatec_memomouse_parser_set_data, /* set_data */
uwatec_memomouse_parser_get_datetime, /* datetime */
uwatec_memomouse_parser_get_field, /* fields */
uwatec_memomouse_parser_samples_foreach, /* samples_foreach */
uwatec_memomouse_parser_destroy /* destroy */
NULL /* destroy */
};
dc_status_t
uwatec_memomouse_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int devtime, dc_ticks_t systime)
{
uwatec_memomouse_parser_t *parser = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
uwatec_memomouse_parser_t *parser = (uwatec_memomouse_parser_t *) malloc (sizeof (uwatec_memomouse_parser_t));
parser = (uwatec_memomouse_parser_t *) dc_parser_allocate (context, &uwatec_memomouse_parser_vtable);
if (parser == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
parser_init (&parser->base, context, &uwatec_memomouse_parser_vtable);
// Set the default values.
parser->devtime = devtime;
parser->systime = systime;
@ -80,16 +79,6 @@ uwatec_memomouse_parser_create (dc_parser_t **out, dc_context_t *context, unsign
}
static dc_status_t
uwatec_memomouse_parser_destroy (dc_parser_t *abstract)
{
// Free memory.
free (abstract);
return DC_STATUS_SUCCESS;
}
static dc_status_t
uwatec_memomouse_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{

View File

@ -55,6 +55,7 @@ static dc_status_t uwatec_meridian_device_foreach (dc_device_t *abstract, dc_div
static dc_status_t uwatec_meridian_device_close (dc_device_t *abstract);
static const dc_device_vtable_t uwatec_meridian_device_vtable = {
sizeof(uwatec_meridian_device_t),
DC_FAMILY_UWATEC_MERIDIAN,
uwatec_meridian_device_set_fingerprint, /* set_fingerprint */
NULL, /* read */
@ -186,19 +187,19 @@ uwatec_meridian_handshake (uwatec_meridian_device_t *device)
dc_status_t
uwatec_meridian_device_open (dc_device_t **out, dc_context_t *context, const char *name)
{
dc_status_t status = DC_STATUS_SUCCESS;
uwatec_meridian_device_t *device = NULL;
if (out == NULL)
return DC_STATUS_INVALIDARGS;
// Allocate memory.
uwatec_meridian_device_t *device = (uwatec_meridian_device_t *) malloc (sizeof (uwatec_meridian_device_t));
device = (uwatec_meridian_device_t *) dc_device_allocate (context, &uwatec_meridian_device_vtable);
if (device == NULL) {
ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY;
}
// Initialize the base class.
device_init (&device->base, context, &uwatec_meridian_device_vtable);
// Set the default values.
device->port = NULL;
device->timestamp = 0;
@ -209,25 +210,23 @@ uwatec_meridian_device_open (dc_device_t **out, dc_context_t *context, const cha
int rc = serial_open (&device->port, context, name);
if (rc == -1) {
ERROR (context, "Failed to open the serial port.");
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_free;
}
// Set the serial communication protocol (57600 8N1).
rc = serial_configure (device->port, 57600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
if (rc == -1) {
ERROR (context, "Failed to set the terminal attributes.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Set the timeout for receiving data (3000ms).
if (serial_set_timeout (device->port, 3000) == -1) {
ERROR (context, "Failed to set the timeout.");
serial_close (device->port);
free (device);
return DC_STATUS_IO;
status = DC_STATUS_IO;
goto error_close;
}
// Make sure everything is in a sane state.
@ -239,24 +238,27 @@ uwatec_meridian_device_open (dc_device_t **out, dc_context_t *context, const cha
*out = (dc_device_t*) device;
return DC_STATUS_SUCCESS;
error_close:
serial_close (device->port);
error_free:
dc_device_deallocate ((dc_device_t *) device);
return status;
}
static dc_status_t
uwatec_meridian_device_close (dc_device_t *abstract)
{
dc_status_t status = DC_STATUS_SUCCESS;
uwatec_meridian_device_t *device = (uwatec_meridian_device_t*) abstract;
// Close the device.
if (serial_close (device->port) == -1) {
free (device);
return DC_STATUS_IO;
dc_status_set_error(&status, DC_STATUS_IO);
}
// Free memory.
free (device);
return DC_STATUS_SUCCESS;
return status;
}

Some files were not shown because too many files have changed in this diff Show More