Merge branch 'master' into Subsurface-branch
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
commit
7c33c633fb
@ -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])
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
306
examples/dctool.c
Normal 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
68
examples/dctool.h
Normal 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
376
examples/dctool_download.c
Normal 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
191
examples/dctool_dump.c
Normal 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
179
examples/dctool_fwupdate.c
Normal 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
105
examples/dctool_help.c
Normal 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
103
examples/dctool_list.c
Normal 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
304
examples/dctool_parse.c
Normal 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
197
examples/dctool_read.c
Normal 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
94
examples/dctool_version.c
Normal 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
200
examples/dctool_write.c
Normal 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
|
||||
};
|
||||
@ -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
58
examples/output-private.h
Normal 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
79
examples/output.c
Normal 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
49
examples/output.h
Normal 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
219
examples/output_raw.c
Normal 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
365
examples/output_xml.c
Normal 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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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"
|
||||
>
|
||||
|
||||
@ -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 \
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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
37
src/common-private.h
Normal 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
34
src/common.c
Normal 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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
|
||||
40
src/device.c
40
src/device.c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
127
src/irda.c
127
src/irda.c
@ -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.
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
39
src/parser.c
39
src/parser.c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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
Loading…
x
Reference in New Issue
Block a user