diff --git a/NEWS b/NEWS index 938041d..7c03239 100644 --- a/NEWS +++ b/NEWS @@ -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) ========================== diff --git a/configure.ac b/configure.ac index 235e8ba..a48b734 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am index 7020e2e..fbaa991 100644 --- a/doc/man/Makefile.am +++ b/doc/man/Makefile.am @@ -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) diff --git a/examples/output_xml.c b/examples/output_xml.c index 237f929..5153fc8 100644 --- a/examples/output_xml.c +++ b/examples/output_xml.c @@ -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, " ", 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, "\n"); break; case DC_SAMPLE_SETPOINT: diff --git a/m4/ax_append_compile_flags.m4 b/m4/ax_append_compile_flags.m4 new file mode 100644 index 0000000..5b6f1af --- /dev/null +++ b/m4/ax_append_compile_flags.m4 @@ -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 +# +# 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 . +# +# 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 diff --git a/m4/ax_append_flag.m4 b/m4/ax_append_flag.m4 new file mode 100644 index 0000000..e8c5312 --- /dev/null +++ b/m4/ax_append_flag.m4 @@ -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 +# Copyright (c) 2011 Maarten Bosmans +# +# 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 . +# +# 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 diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4 new file mode 100644 index 0000000..dcabb92 --- /dev/null +++ b/m4/ax_check_compile_flag.m4 @@ -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 +# Copyright (c) 2011 Maarten Bosmans +# +# 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 . +# +# 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 diff --git a/m4/ax_require_defined.m4 b/m4/ax_require_defined.m4 new file mode 100644 index 0000000..17c3eab --- /dev/null +++ b/m4/ax_require_defined.m4 @@ -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 +# +# 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 diff --git a/src/bluetooth.c b/src/bluetooth.c index bc9ffe0..01a3e96 100644 --- a/src/bluetooth.c +++ b/src/bluetooth.c @@ -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) diff --git a/src/descriptor.c b/src/descriptor.c index 01dbd69..a8c8a1a 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -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 */ diff --git a/src/device.c b/src/device.c index 7980186..49f845a 100644 --- a/src/device.c +++ b/src/device.c @@ -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; diff --git a/src/divesystem_idive_parser.c b/src/divesystem_idive_parser.c index ca5c2b1..24f7e53 100644 --- a/src/divesystem_idive_parser.c +++ b/src/divesystem_idive_parser.c @@ -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; } - sample.deco.time = tts; if (callback) callback (DC_SAMPLE_DECO, sample, userdata); } diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index 267929c..ed5c824 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -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) { diff --git a/src/irda.c b/src/irda.c index d085ec0..1a2c38c 100644 --- a/src/irda.c +++ b/src/irda.c @@ -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) diff --git a/src/oceanic_common.c b/src/oceanic_common.c index 427b326..43bc06d 100644 --- a/src/oceanic_common.c +++ b/src/oceanic_common.c @@ -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) diff --git a/src/serial_posix.c b/src/serial_posix.c index 9327d96..7f07206 100644 --- a/src/serial_posix.c +++ b/src/serial_posix.c @@ -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) diff --git a/src/serial_win32.c b/src/serial_win32.c index 40cddf9..540ec11 100644 --- a/src/serial_win32.c +++ b/src/serial_win32.c @@ -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) diff --git a/src/shearwater_common.c b/src/shearwater_common.c index 2546998..58fd3a3 100644 --- a/src/shearwater_common.c +++ b/src/shearwater_common.c @@ -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; } diff --git a/src/shearwater_common.h b/src/shearwater_common.h index 406f151..4253a00 100644 --- a/src/shearwater_common.h +++ b/src/shearwater_common.h @@ -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); diff --git a/src/shearwater_petrel.c b/src/shearwater_petrel.c index 7558c54..5f38aaa 100644 --- a/src/shearwater_petrel.c +++ b/src/shearwater_petrel.c @@ -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; } + // 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: + model = PREDATOR; + break; + case 0x0606: + case 0x0A0A: // Nerd 1 + case 0x0E0D: // Nerd 2 + model = NERD; + break; + case 0x0404: + case 0x0909: // Petrel 1 + case 0x0B0B: // Petrel 1 (newer hardware) + model = PETREL; + break; + case 0x0505: + case 0x0808: // Petrel 2 + model = PETREL; + break; + case 0x0707: // documentation list 0C0D for both Perdix and Perdix AI :-( + model = PERDIX; + break; + case 0x0C0C: + case 0x0C0D: + case 0x0D0D: + model = PERDIXAI; + break; + default: + model = PETREL; + WARNING (abstract->context, "Unknown hardware type %04x. Assuming Petrel.", hardware); + } + // 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) { - case 0x0101: - case 0x0202: - devinfo.model = PREDATOR; - break; - case 0x0606: - case 0x0A0A: - devinfo.model = NERD; - break; - case 0x0404: - case 0x0909: - case 0x0B0B: - devinfo.model = PETREL; - break; - case 0x0505: - case 0x0808: - devinfo.model = PETREL2; - break; - case 0x0707: // documentation list 0C0D for both Perdix and Perdix AI :-( - devinfo.model = PERDIX; - break; - case 0x0C0C: - case 0x0C0D: - case 0x0D0D: - devinfo.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."); - } + 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); diff --git a/src/shearwater_predator.c b/src/shearwater_predator.c index 42a579b..a47d414 100644 --- a/src/shearwater_predator.c +++ b/src/shearwater_predator.c @@ -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); } diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index 992169c..6e81083 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -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 haven’t been set up + if (data[offset + 21] < 0xF0) { sample.rbt = data[offset + 21]; if (callback) callback (DC_SAMPLE_RBT, sample, userdata); } diff --git a/src/suunto_common2.c b/src/suunto_common2.c index 80b2477..4aa1699 100644 --- a/src/suunto_common2.c +++ b/src/suunto_common2.c @@ -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) diff --git a/src/suunto_eonsteel.c b/src/suunto_eonsteel.c index 0f656ad..f4dcc2b 100644 --- a/src/suunto_eonsteel.c +++ b/src/suunto_eonsteel.c @@ -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 diff --git a/src/usbhid.c b/src/usbhid.c index 06a6165..1b0931f 100644 --- a/src/usbhid.c +++ b/src/usbhid.c @@ -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)