Merge tag 'v0.6.0' of git://git.libdivecomputer.org/libdivecomputer into Subsurface-branch

Sync up with upstream cersion 0.6.0.

Annoying merge, mainly because a lof of the changes Jef had done are
actually changes that came from our Subsurface branch, but in a
different form, because Jef doesn't actually take patches directly from
us.

Why? I don't know.

* tag 'v0.6.0' of git://git.libdivecomputer.org/libdivecomputer:
  Release version 0.6.0
  Fix some potential buffer overflows
  Fix some casts with constant pointers
  Enable some useful compiler warnings by default
  Generate html documentation from the manpages
  Fix the decoding of the ndl/deco information
  Decode the firmware version for the iDive series
  Add support for the Suunto Eon Core
  Locate the most recent dive
  Add EON Steel time sync capability
  Improve the progress events
  Detect the model number using the hardware type
  Shearwater: add support for remaining gas time
  Shearwater: extract tank sensor data for log version 7
  Shearwater: extract log version from header
This commit is contained in:
Linus Torvalds 2017-12-04 10:18:23 -08:00
commit 54f6bff929
25 changed files with 541 additions and 122 deletions

37
NEWS
View File

@ -1,3 +1,40 @@
Version 0.6.0 (2017-11-24)
==========================
The v0.6.0 release adds support for several new devices, introduces two
new features and fixes a couple of bugs. There are a few minor backwards
incompatible changes, but most applications won't be affected by those.
New features:
* Add support for new backends:
- g2: Scubapro G2, Aladin Sport Matrix, Aladin Square
* Add support for many new devices:
- Aqualung: i200, i750TC
- Cochran: Commander I, II and TM
- Cressi: Drake
- Hollis: DG02
- Mares: Quad
- Oceanic: F10
- Ratio: iX3M and iDive series
- Suunto: D4f, Eon Core
- Uwatec: Aladin Tec 3G
* Add basic timezone support
* Add support for synchronizing the device clock
* Document the public api with man pages
Removed/changed features:
* Remove the deprecated gas change events
* Remove the deprecated vendor_product_parser_create(),
vendor_product_device_open() and vendor_product_extract_dives()
functions from the public api
* Remove the hw_{frog,ostc,ostc3}_device_clock() functions
Bug fixes:
* Many small improvements
Version 0.5.0 (2016-09-30)
==========================

View File

@ -64,8 +64,10 @@ AM_CONDITIONAL([ENABLE_DOC], [test "x$enable_doc" = "xyes"])
AC_PROG_CC
AC_PROG_CC_C99
AC_CHECK_PROGS([DOXYGEN], [doxygen])
AC_CHECK_PROGS([MANDOC], [mandoc])
AM_CONDITIONAL([HAVE_DOXYGEN],[test -n "$DOXYGEN"])
AM_CONDITIONAL([HAVE_MANDOC],[test -n "$MANDOC"])
# Enable automake silent build rules.
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
@ -169,6 +171,23 @@ AC_FUNC_STRERROR_R
AC_CHECK_FUNCS([localtime_r gmtime_r timegm _mkgmtime])
AC_CHECK_FUNCS([getopt_long])
# Checks for supported compiler options.
AX_APPEND_COMPILE_FLAGS([ \
-pedantic \
-Wall \
-Wextra \
-Wshadow \
-Wrestrict \
-Wformat=2 \
-Wwrite-strings \
-Wcast-qual \
-Wpointer-arith \
-Wstrict-prototypes \
-Wmissing-prototypes \
-Wmissing-declarations \
-Wno-unused-parameter \
])
# Versioning.
AC_SUBST([DC_VERSION],[dc_version])
AC_SUBST([DC_VERSION_MAJOR],[dc_version_major])

View File

@ -1,4 +1,4 @@
dist_man_MANS = \
MANPAGES = \
dc_buffer_append.3 \
dc_buffer_free.3 \
dc_buffer_get_data.3 \
@ -32,3 +32,18 @@ dist_man_MANS = \
dc_parser_samples_foreach.3 \
dc_parser_set_data.3 \
libdivecomputer.3
HTMLPAGES = $(MANPAGES:%=%.html)
dist_man_MANS = $(MANPAGES)
if HAVE_MANDOC
doc_DATA = $(HTMLPAGES)
endif
SUFFIXES = .3 .3.html
.3.3.html:
$(AM_V_GEN) $(MANDOC) -Thtml -Ostyle=mandoc.css,man=%N.%S.html $< > $@
CLEANFILES = $(HTMLPAGES)

View File

@ -142,7 +142,7 @@ sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata)
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, "%02X", ((const unsigned char *) value.vendor.data)[i]);
fprintf (sampledata->ostream, "</vendor>\n");
break;
case DC_SAMPLE_SETPOINT:

View File

@ -0,0 +1,67 @@
# ============================================================================
# https://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html
# ============================================================================
#
# SYNOPSIS
#
# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# For every FLAG1, FLAG2 it is checked whether the compiler works with the
# flag. If it does, the flag is added FLAGS-VARIABLE
#
# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
# CFLAGS) is used. During the check the flag is always added to the
# current language's flags.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
#
# NOTE: This macro depends on the AX_APPEND_FLAG and
# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with
# AX_APPEND_LINK_FLAGS.
#
# LICENSE
#
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program 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 General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 6
AC_DEFUN([AX_APPEND_COMPILE_FLAGS],
[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG])
AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
for flag in $1; do
AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3], [$4])
done
])dnl AX_APPEND_COMPILE_FLAGS

71
m4/ax_append_flag.m4 Normal file
View File

@ -0,0 +1,71 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_append_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE])
#
# DESCRIPTION
#
# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space
# added in between.
#
# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains
# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly
# FLAG.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program 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 General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 7
AC_DEFUN([AX_APPEND_FLAG],
[dnl
AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
AS_VAR_SET_IF(FLAGS,[
AS_CASE([" AS_VAR_GET(FLAGS) "],
[*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
[
AS_VAR_APPEND(FLAGS,[" $1"])
AC_RUN_LOG([: FLAGS="$FLAGS"])
])
],
[
AS_VAR_SET(FLAGS,[$1])
AC_RUN_LOG([: FLAGS="$FLAGS"])
])
AS_VAR_POPDEF([FLAGS])dnl
])dnl AX_APPEND_FLAG

View File

@ -0,0 +1,74 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
#
# DESCRIPTION
#
# Check whether the given FLAG works with the current language's compiler
# or gives an error. (Warnings, however, are ignored)
#
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
# success/failure.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program 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 General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 5
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
[AS_VAR_SET(CACHEVAR,[yes])],
[AS_VAR_SET(CACHEVAR,[no])])
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
AS_VAR_IF(CACHEVAR,yes,
[m4_default([$2], :)],
[m4_default([$3], :)])
AS_VAR_POPDEF([CACHEVAR])dnl
])dnl AX_CHECK_COMPILE_FLAGS

37
m4/ax_require_defined.m4 Normal file
View File

@ -0,0 +1,37 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_require_defined.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_REQUIRE_DEFINED(MACRO)
#
# DESCRIPTION
#
# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
# been defined and thus are available for use. This avoids random issues
# where a macro isn't expanded. Instead the configure script emits a
# non-fatal:
#
# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
#
# It's like AC_REQUIRE except it doesn't expand the required macro.
#
# Here's an example:
#
# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
#
# LICENSE
#
# Copyright (c) 2014 Mike Frysinger <vapier@gentoo.org>
#
# Copying and distribution of this file, with or without modification, are
# permitted in any medium without royalty provided the copyright notice
# and this notice are preserved. This file is offered as-is, without any
# warranty.
#serial 2
AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
])dnl AX_REQUIRE_DEFINED

View File

@ -571,7 +571,7 @@ dc_bluetooth_write (dc_bluetooth_t *device, const void *data, size_t size, size_
break; // Timeout.
}
s_ssize_t n = send (device->fd, (char*) data + nbytes, size - nbytes, 0);
s_ssize_t n = send (device->fd, (const char *) data + nbytes, size - nbytes, 0);
if (n < 0) {
s_errcode_t errcode = S_ERRNO;
if (errcode == S_EINTR || errcode == S_EAGAIN)
@ -591,7 +591,7 @@ dc_bluetooth_write (dc_bluetooth_t *device, const void *data, size_t size, size_
}
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes);
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (const unsigned char *) data, nbytes);
out_invalidargs:
if (actual)

View File

@ -290,10 +290,11 @@ static const dc_descriptor_t g_descriptors[] = {
{"Shearwater", "Predator", DC_FAMILY_SHEARWATER_PREDATOR, 2}, // BT
/* Shearwater Petrel family */
{"Shearwater", "Petrel", DC_FAMILY_SHEARWATER_PETREL, 3}, // BT // BLE
{"Shearwater", "Petrel 2", DC_FAMILY_SHEARWATER_PETREL, 4}, // BT // BLE
{"Shearwater", "Nerd", DC_FAMILY_SHEARWATER_PETREL, 5}, // BT
{"Shearwater", "Perdix", DC_FAMILY_SHEARWATER_PETREL, 6}, // BT // BLE
{"Shearwater", "Perdix AI", DC_FAMILY_SHEARWATER_PETREL, 7}, // BLE
{"Shearwater", "Petrel 2", DC_FAMILY_SHEARWATER_PETREL, 3}, // BT // BLE
{"Shearwater", "Nerd", DC_FAMILY_SHEARWATER_PETREL, 4}, // BT
{"Shearwater", "Nerd 2", DC_FAMILY_SHEARWATER_PETREL, 4}, // BLE
{"Shearwater", "Perdix", DC_FAMILY_SHEARWATER_PETREL, 5}, // BT // BLE
{"Shearwater", "Perdix AI", DC_FAMILY_SHEARWATER_PETREL, 6}, // BLE
/* Dive Rite NiTek Q */
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0},
/* Citizen Hyper Aqualand */

View File

@ -408,7 +408,7 @@ dc_device_close (dc_device_t *device)
void
device_event_emit (dc_device_t *device, dc_event_type_t event, const void *data)
{
dc_event_progress_t *progress = (dc_event_progress_t *) data;
const dc_event_progress_t *progress = (const dc_event_progress_t *) data;
// Check the event data for errors.
switch (event) {
@ -436,10 +436,10 @@ device_event_emit (dc_device_t *device, dc_event_type_t event, const void *data)
// Cache the event data.
switch (event) {
case DC_EVENT_DEVINFO:
device->devinfo = *(dc_event_devinfo_t *) data;
device->devinfo = *(const dc_event_devinfo_t *) data;
break;
case DC_EVENT_CLOCK:
device->clock = *(dc_event_clock_t *) data;
device->clock = *(const dc_event_clock_t *) data;
break;
default:
break;

View File

@ -272,12 +272,14 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
unsigned int beginpressure = 0;
unsigned int endpressure = 0;
unsigned int firmware = 0;
unsigned int apos4 = 0;
unsigned int nsamples = array_uint16_le (data + 1);
unsigned int samplesize = SZ_SAMPLE_IDIVE;
if (parser->model >= IX3M_EASY) {
// Detect the APOS4 firmware.
unsigned int firmware = array_uint32_le(data + 0x2A);
unsigned int apos4 = (firmware / 10000000) >= 4;
firmware = array_uint32_le(data + 0x2A);
apos4 = (firmware / 10000000) >= 4;
if (apos4) {
// Dive downloaded and recorded with the APOS4 firmware.
samplesize = SZ_SAMPLE_IX3M_APOS4;
@ -289,6 +291,8 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
// Dive downloaded and recorded with an older firmware.
samplesize = SZ_SAMPLE_IX3M;
}
} else {
firmware = array_uint32_le(data + 0x2E);
}
unsigned int offset = parser->headersize;
@ -366,17 +370,31 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
}
// Deco stop / NDL.
unsigned int deco = array_uint16_le (data + offset + 21);
unsigned int tts = array_uint16_le (data + offset + 23);
if (tts != 0xFFFF) {
if (deco) {
unsigned int decostop = 0, decotime = 0, tts = 0;
if (apos4) {
decostop = array_uint16_le (data + offset + 21);
decotime = array_uint16_le (data + offset + 23);
tts = array_uint16_le (data + offset + 25);
if (tts == 0x7FFF) {
tts = INVALID;
}
} else {
decostop = array_uint16_le (data + offset + 21);
tts = array_uint16_le (data + offset + 23);
if (tts == 0xFFFF) {
tts = INVALID;
}
}
if (tts != INVALID) {
if (decostop) {
sample.deco.type = DC_DECO_DECOSTOP;
sample.deco.depth = deco / 10.0;
sample.deco.depth = decostop / 10.0;
sample.deco.time = apos4 ? decotime : tts;
} else {
sample.deco.type = DC_DECO_NDL;
sample.deco.depth = 0.0;
}
sample.deco.time = tts;
}
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
}

View File

@ -685,6 +685,14 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
unsigned int header = parser->header;
const hw_ostc_layout_t *layout = parser->layout;
// Check the header length.
if (version == 0x23 || version == 0x24) {
if (size < header + 5) {
ERROR (abstract->context, "Buffer overflow detected!");
return DC_STATUS_DATAFORMAT;
}
}
// Get the sample rate.
unsigned int samplerate = 0;
if (version == 0x23 || version == 0x24)
@ -711,6 +719,14 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
return DC_STATUS_DATAFORMAT;
}
// Check the header length.
if (version == 0x23 || version == 0x24) {
if (size < header + 5 + 3 * nconfig) {
ERROR (abstract->context, "Buffer overflow detected!");
return DC_STATUS_DATAFORMAT;
}
}
// Get the extended sample configuration.
hw_ostc_sample_info_t info[MAXCONFIG] = {{0}};
for (unsigned int i = 0; i < nconfig; ++i) {

View File

@ -535,7 +535,7 @@ dc_irda_write (dc_irda_t *device, const void *data, size_t size, size_t *actual)
break; // Timeout.
}
s_ssize_t n = send (device->fd, (char*) data + nbytes, size - nbytes, 0);
s_ssize_t n = send (device->fd, (const char *) data + nbytes, size - nbytes, 0);
if (n < 0) {
s_errcode_t errcode = S_ERRNO;
if (errcode == S_EINTR || errcode == S_EAGAIN)
@ -555,7 +555,7 @@ dc_irda_write (dc_irda_t *device, const void *data, size_t size, size_t *actual)
}
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes);
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (const unsigned char *) data, nbytes);
out_invalidargs:
if (actual)

View File

@ -30,7 +30,7 @@
#include "rbstream.h"
#include "array.h"
#define VTABLE(abstract) ((oceanic_common_device_vtable_t *) abstract->vtable)
#define VTABLE(abstract) ((const oceanic_common_device_vtable_t *) abstract->vtable)
#define RB_LOGBOOK_DISTANCE(a,b,l) ringbuffer_distance (a, b, 0, l->rb_logbook_begin, l->rb_logbook_end)
#define RB_LOGBOOK_INCR(a,b,l) ringbuffer_increment (a, b, l->rb_logbook_begin, l->rb_logbook_end)

View File

@ -781,7 +781,7 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act
}
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes);
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (const unsigned char *) data, nbytes);
out_invalidargs:
if (actual)

View File

@ -528,7 +528,7 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act
}
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, dwWritten);
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (const unsigned char *) data, dwWritten);
out_invalidargs:
if (actual)

View File

@ -343,7 +343,7 @@ shearwater_common_transfer (shearwater_common_device_t *device, const unsigned c
dc_status_t
shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buffer, unsigned int address, unsigned int size, unsigned int compression)
shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buffer, unsigned int address, unsigned int size, unsigned int compression, dc_event_progress_t *progress)
{
dc_device_t *abstract = (dc_device_t *) device;
dc_status_t rc = DC_STATUS_SUCCESS;
@ -371,9 +371,11 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
}
// Enable progress notifications.
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
progress.maximum = 3 + size + 1;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
unsigned int initial = 0, current = 0, maximum = 3 + size + 1;
if (progress) {
initial = progress->current;
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
}
// Transfer the init request.
rc = shearwater_common_transfer (device, req_init, sizeof (req_init), response, 3, &n);
@ -388,8 +390,11 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
}
// Update and emit a progress event.
progress.current += 3;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
if (progress) {
current += 3;
progress->current = initial + STEP (current, maximum);
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
}
unsigned int done = 0;
unsigned char block = 1;
@ -416,8 +421,11 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
}
// Update and emit a progress event.
progress.current += length;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
if (progress) {
current += length;
progress->current = initial + STEP (current, maximum);
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
}
if (compression) {
if (shearwater_common_decompress_lre (response + 2, length, buffer, &done) != 0) {
@ -455,8 +463,11 @@ shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buf
}
// Update and emit a progress event.
progress.current += 1;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
if (progress) {
current += 1;
progress->current = initial + STEP (current, maximum);
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
}
return DC_STATUS_SUCCESS;
}

View File

@ -31,14 +31,16 @@ extern "C" {
#define ID_SERIAL 0x8010
#define ID_FIRMWARE 0x8011
#define ID_HARDWARE_TYPE 0x8050
#define ID_HARDWARE 0x8050
#define PREDATOR 2
#define PETREL 3
#define PETREL2 4
#define NERD 5
#define PERDIX 6
#define PERDIXAI 7
#define NERD 4
#define PERDIX 5
#define PERDIXAI 6
#define NSTEPS 10000
#define STEP(i,n) ((NSTEPS * (i) + (n) / 2) / (n))
typedef struct shearwater_common_device_t {
dc_device_t base;
@ -55,7 +57,7 @@ dc_status_t
shearwater_common_transfer (shearwater_common_device_t *device, const unsigned char input[], unsigned int isize, unsigned char output[], unsigned int osize, unsigned int *actual);
dc_status_t
shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buffer, unsigned int address, unsigned int size, unsigned int compression);
shearwater_common_download (shearwater_common_device_t *device, dc_buffer_t *buffer, unsigned int address, unsigned int size, unsigned int compression, dc_event_progress_t *progress);
dc_status_t
shearwater_common_identifier (shearwater_common_device_t *device, dc_buffer_t *buffer, unsigned int id);

View File

@ -168,6 +168,11 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
return DC_STATUS_NOMEMORY;
}
// Enable progress notifications.
unsigned int current = 0, maximum = 0;
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
// Read the serial number.
rc = shearwater_common_identifier (&device->base, buffer, ID_SERIAL);
if (rc != DC_STATUS_SUCCESS) {
@ -200,8 +205,8 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
// Convert to a number.
unsigned int firmware = str2num (dc_buffer_get_data (buffer), dc_buffer_get_size (buffer), 1);
// get the product information
rc = shearwater_common_identifier (&device->base, buffer, ID_HARDWARE_TYPE);
// Read the hardware type.
rc = shearwater_common_identifier (&device->base, buffer, ID_HARDWARE);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to read the hardware type.");
dc_buffer_free (buffer);
@ -209,51 +214,59 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
return rc;
}
// Emit a device info event.
dc_event_devinfo_t devinfo;
if (dc_buffer_get_size (buffer) == 2) {
unsigned short model_code = array_uint16_be(dc_buffer_get_data (buffer));
switch (model_code) {
// Convert and map to the model number.
unsigned int hardware = array_uint_be (dc_buffer_get_data (buffer), dc_buffer_get_size (buffer));
unsigned int model = 0;
switch (hardware) {
case 0x0101:
case 0x0202:
devinfo.model = PREDATOR;
model = PREDATOR;
break;
case 0x0606:
case 0x0A0A:
devinfo.model = NERD;
case 0x0A0A: // Nerd 1
case 0x0E0D: // Nerd 2
model = NERD;
break;
case 0x0404:
case 0x0909:
case 0x0B0B:
devinfo.model = PETREL;
case 0x0909: // Petrel 1
case 0x0B0B: // Petrel 1 (newer hardware)
model = PETREL;
break;
case 0x0505:
case 0x0808:
devinfo.model = PETREL2;
case 0x0808: // Petrel 2
model = PETREL;
break;
case 0x0707: // documentation list 0C0D for both Perdix and Perdix AI :-(
devinfo.model = PERDIX;
model = PERDIX;
break;
case 0x0C0C:
case 0x0C0D:
case 0x0D0D:
devinfo.model = PERDIXAI;
model = PERDIXAI;
break;
default:
devinfo.model = PETREL;
ERROR (abstract->context, "Unknown model code - assuming Petrel.");
}
} else {
devinfo.model = PERDIX;
ERROR (abstract->context, "Failed to read hardware type - assuming Petrel.");
model = PETREL;
WARNING (abstract->context, "Unknown hardware type %04x. Assuming Petrel.", hardware);
}
// Emit a device info event.
dc_event_devinfo_t devinfo;
devinfo.model = model;
devinfo.firmware = firmware;
devinfo.serial = array_uint32_be (serial);
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
while (1) {
// Update the progress state.
// Assume the worst case scenario of a full manifest, and adjust the
// value with the actual number of dives after the manifest has been
// processed.
maximum += 1 + RECORD_COUNT;
// Download a manifest.
rc = shearwater_common_download (&device->base, buffer, MANIFEST_ADDR, MANIFEST_SIZE, 0);
progress.current = NSTEPS * current;
progress.maximum = NSTEPS * maximum;
rc = shearwater_common_download (&device->base, buffer, MANIFEST_ADDR, MANIFEST_SIZE, 0, &progress);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to download the manifest.");
dc_buffer_free (buffer);
@ -282,6 +295,10 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
count++;
}
// Update the progress state.
current += 1;
maximum -= RECORD_COUNT - count;
// Append the manifest records to the main buffer.
if (!dc_buffer_append (manifests, data, count * RECORD_SIZE)) {
ERROR (abstract->context, "Insufficient buffer space available.");
@ -295,6 +312,11 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
break;
}
// Update and emit a progress event.
progress.current = NSTEPS * current;
progress.maximum = NSTEPS * maximum;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
// Cache the buffer pointer and size.
unsigned char *data = dc_buffer_get_data (manifests);
unsigned int size = dc_buffer_get_size (manifests);
@ -305,7 +327,9 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
unsigned int address = array_uint32_be (data + offset + 20);
// Download the dive.
rc = shearwater_common_download (&device->base, buffer, DIVE_ADDR + address, DIVE_SIZE, 1);
progress.current = NSTEPS * current;
progress.maximum = NSTEPS * maximum;
rc = shearwater_common_download (&device->base, buffer, DIVE_ADDR + address, DIVE_SIZE, 1, &progress);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to download the dive.");
dc_buffer_free (buffer);
@ -313,6 +337,9 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
return rc;
}
// Update the progress state.
current += 1;
unsigned char *buf = dc_buffer_get_data (buffer);
unsigned int len = dc_buffer_get_size (buffer);
if (callback && !callback (buf, len, buf + 12, sizeof (device->fingerprint), userdata))
@ -321,6 +348,11 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
offset += RECORD_SIZE;
}
// Update and emit a progress event.
progress.current = NSTEPS * current;
progress.maximum = NSTEPS * maximum;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
dc_buffer_free (manifests);
dc_buffer_free (buffer);

View File

@ -30,9 +30,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &shearwater_predator_device_vtable)
#define PREDATOR 2
#define PETREL 3
#define SZ_BLOCK 0x80
#define SZ_MEMORY 0x20080
@ -136,7 +133,12 @@ shearwater_predator_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
return DC_STATUS_NOMEMORY;
}
return shearwater_common_download (device, buffer, 0xDD000000, SZ_MEMORY, 0);
// Enable progress notifications.
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
progress.current = 0;
progress.maximum = NSTEPS;
return shearwater_common_download (device, buffer, 0xDD000000, SZ_MEMORY, 0, &progress);
}

View File

@ -65,6 +65,7 @@ struct shearwater_predator_parser_t {
unsigned int samplesize;
// Cached fields.
unsigned int cached;
unsigned int logversion;
unsigned int headersize;
unsigned int footersize;
unsigned int ngasmixes;
@ -73,7 +74,6 @@ struct shearwater_predator_parser_t {
double calibration[3];
unsigned int serial;
dc_divemode_t mode;
unsigned char logversion;
/* String fields */
dc_field_string_t strings[MAXSTRINGS];
@ -151,6 +151,7 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsig
// Set the default values.
parser->cached = 0;
parser->logversion = 0;
parser->headersize = 0;
parser->footersize = 0;
parser->ngasmixes = 0;
@ -173,6 +174,7 @@ shearwater_predator_parser_set_data (dc_parser_t *abstract, const unsigned char
// Reset the cache.
parser->cached = 0;
parser->logversion = 0;
parser->headersize = 0;
parser->footersize = 0;
parser->ngasmixes = 0;
@ -366,10 +368,10 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
// Log versions before 6 weren't reliably stored in the data, but
// 6 is also the oldest version that we assume in our code
parser->logversion = 6;
unsigned int logversion = 6;
if (data[127] > 6)
parser->logversion = data[127];
INFO(abstract->context, "Shearwater log version %u\n", parser->logversion);
logversion = data[127];
INFO(abstract->context, "Shearwater log version %u\n", logversion);
memset(parser->strings, 0, sizeof(parser->strings));
@ -437,7 +439,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
}
// Transmitter battery levels
if (parser->logversion >= 7) {
if (logversion >= 7) {
// T1 at offset 27, T2 at offset 19
t1_battery |= battery_state(data + offset + 27);
t2_battery |= battery_state(data + offset + 19);
@ -461,6 +463,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
}
// Cache the data for later use.
parser->logversion = logversion;
parser->headersize = headersize;
parser->footersize = footersize;
parser->ngasmixes = ngasmixes;
@ -690,27 +693,38 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal
// for logversion 7 and newer (introduced for Perdix AI)
// detect tank pressure
if (parser->logversion >= 7) {
// Pressure (2 psi).
// 0xFFFF is not paired / no coms for 90 seconds
// 0xFFFE no coms for 30 seconds
// top 4 bits battery level:
// 0 - normal, 1 - critical, 2 - warning
// Tank pressure
// Values above 0xFFF0 are special codes:
// 0xFFFF AI is off
// 0xFFFE No comms for 90 seconds+
// 0xFFFD No comms for 30 seconds
// 0xFFFC Transmitter not paired
// For regular values, the top 4 bits contain the battery
// level (0=normal, 1=critical, 2=warning), and the lower 12
// bits the tank pressure in units of 2 psi.
unsigned int pressure = array_uint16_be (data + offset + 27);
if ((pressure & 0xFFF0) != 0xFFF0) {
if (pressure < 0xFFF0) {
pressure &= 0x0FFF;
sample.pressure.tank = 0;
sample.pressure.value = pressure * 2 * PSI / BAR;
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
}
pressure = array_uint16_be (data + offset + 19);
if ((pressure & 0xFFF0) != 0xFFF0) {
if (pressure < 0xFFF0) {
pressure &= 0x0FFF;
sample.pressure.tank = 1;
sample.pressure.value = pressure * 2 * PSI / BAR;
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
}
// Gas time remaining in minutes
if (data[offset + 21] < 0xFBu) {
// Values above 0xF0 are special codes:
// 0xFF Not paired
// 0xFE No communication
// 0xFD Not available in current mode
// 0xFC Not available because of DECO
// 0xFB Tank size or max pressure havent been set up
if (data[offset + 21] < 0xF0) {
sample.rbt = data[offset + 21];
if (callback) callback (DC_SAMPLE_RBT, sample, userdata);
}

View File

@ -38,7 +38,7 @@
#define RB_PROFILE_DISTANCE(l,a,b,m) ringbuffer_distance (a, b, m, l->rb_profile_begin, l->rb_profile_end)
#define VTABLE(abstract) ((suunto_common2_device_vtable_t *) abstract->vtable)
#define VTABLE(abstract) ((const suunto_common2_device_vtable_t *) abstract->vtable)
void
suunto_common2_device_init (suunto_common2_device_t *device)

View File

@ -31,8 +31,12 @@
#include "usbhid.h"
#include "platform.h"
#define EONSTEEL 0
#define EONCORE 1
typedef struct suunto_eonsteel_device_t {
dc_device_t base;
unsigned int model;
unsigned int magic;
unsigned short seq;
unsigned char version[0x30];
@ -73,7 +77,7 @@ struct directory_entry {
static dc_status_t suunto_eonsteel_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
static dc_status_t suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
static dc_status_t suunto_eonsteel_timesync(dc_device_t *abstract, const dc_datetime_t *datetime);
static dc_status_t suunto_eonsteel_device_timesync(dc_device_t *abstract, const dc_datetime_t *datetime);
static dc_status_t suunto_eonsteel_device_close(dc_device_t *abstract);
static const dc_device_vtable_t suunto_eonsteel_device_vtable = {
@ -84,7 +88,7 @@ static const dc_device_vtable_t suunto_eonsteel_device_vtable = {
NULL, /* write */
NULL, /* dump */
suunto_eonsteel_device_foreach, /* foreach */
suunto_eonsteel_timesync, /* timesync */
suunto_eonsteel_device_timesync, /* timesync */
suunto_eonsteel_device_close /* close */
};
@ -740,6 +744,7 @@ suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, const char
return DC_STATUS_NOMEMORY;
// Set up the magic handshake fields
eon->model = model;
eon->magic = INIT_MAGIC;
eon->seq = INIT_SEQ;
memset (eon->version, 0, sizeof (eon->version));
@ -812,26 +817,24 @@ suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callbac
dc_buffer_t *file;
char pathname[64];
unsigned int time;
unsigned int count = 0;
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
if (get_file_list(eon, &de) < 0)
return DC_STATUS_IO;
// Emit a device info event.
dc_event_devinfo_t devinfo;
devinfo.model = 0;
devinfo.model = eon->model;
devinfo.firmware = array_uint32_be (eon->version + 0x20);
devinfo.serial = array_convert_str2num(eon->version + 0x10, 16);
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
count = count_dir_entries(de);
if (count == 0) {
if (get_file_list(eon, &de) < 0)
return DC_STATUS_IO;
if (de == NULL) {
return DC_STATUS_SUCCESS;
}
file = dc_buffer_new(0);
progress.maximum = count;
progress.maximum = count_dir_entries(de);
progress.current = 0;
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
@ -890,12 +893,12 @@ suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callbac
return device_is_cancelled(abstract) ? DC_STATUS_CANCELLED : DC_STATUS_SUCCESS;
}
static dc_status_t suunto_eonsteel_timesync(dc_device_t *abstract, const dc_datetime_t *datetime)
static dc_status_t suunto_eonsteel_device_timesync(dc_device_t *abstract, const dc_datetime_t *datetime)
{
suunto_eonsteel_device_t *eon = (suunto_eonsteel_device_t *) abstract;
unsigned char result[64], cmd[64];
int year, month, day;
int hour, min, sec, msec;
unsigned char result[64], cmd[8];
unsigned int year, month, day;
unsigned int hour, min, msec;
int rc;
year = datetime->year;
@ -903,23 +906,23 @@ static dc_status_t suunto_eonsteel_timesync(dc_device_t *abstract, const dc_date
day = datetime->day;
hour = datetime->hour;
min = datetime->minute;
sec = datetime->second;
msec = datetime->second * 1000;
INFO(eon->base.context, "SET_TIME: %d/%d/%d %d:%02d:%02d.%03d",
year, month, day, hour, min, sec, msec);
msec = sec * 1000;
cmd[0] = year & 255;
cmd[0] = year & 0xFF;
cmd[1] = year >> 8;
cmd[2] = month;
cmd[3] = day;
cmd[4] = hour;
cmd[5] = min;
cmd[6] = msec & 255;
cmd[6] = msec & 0xFF;
cmd[7] = msec >> 8;
return send_receive(eon, CMD_SET_TIME, 8, cmd, sizeof(result), result);
rc = send_receive(eon, CMD_SET_TIME, sizeof(cmd), cmd, sizeof(result), result);
if (rc < 0) {
return DC_STATUS_IO;
}
return DC_STATUS_SUCCESS;
}
static dc_status_t

View File

@ -598,7 +598,7 @@ out:
}
#endif
HEXDUMP (usbhid->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes);
HEXDUMP (usbhid->context, DC_LOGLEVEL_INFO, "Write", (const unsigned char *) data, nbytes);
out_invalidargs:
if (actual)