Compare commits
3 Commits
Subsurface
...
GarminMTPs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c9537fb0fa | ||
|
|
c7f67509d4 | ||
|
|
9de9efcae0 |
173
.github/workflows/build.yml
vendored
173
.github/workflows/build.yml
vendored
@ -1,173 +0,0 @@
|
||||
name: Build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
linux:
|
||||
|
||||
name: Linux
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
compiler: [gcc, clang]
|
||||
|
||||
env:
|
||||
CC: ${{ matrix.compiler }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install libbluetooth-dev libusb-1.0-0-dev
|
||||
- run: autoreconf --install --force
|
||||
- run: ./configure --prefix=/usr
|
||||
- run: make
|
||||
- run: make distcheck
|
||||
- name: Package artifacts
|
||||
run: |
|
||||
make install DESTDIR=$PWD/artifacts
|
||||
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ github.job }}-${{ matrix.compiler }}
|
||||
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
|
||||
|
||||
mac:
|
||||
|
||||
name: Mac
|
||||
|
||||
runs-on: macos-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
compiler: [gcc, clang]
|
||||
|
||||
env:
|
||||
CC: ${{ matrix.compiler }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install dependencies
|
||||
run: brew install autoconf automake libtool hidapi libusb
|
||||
- run: autoreconf --install --force
|
||||
- run: ./configure --prefix=/usr
|
||||
- run: make
|
||||
- run: make distcheck
|
||||
- name: Package artifacts
|
||||
run: |
|
||||
make install DESTDIR=$PWD/artifacts
|
||||
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ github.job }}-${{ matrix.compiler }}
|
||||
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
|
||||
|
||||
windows:
|
||||
|
||||
name: Windows
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [i686, x86_64]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install gcc-mingw-w64 binutils-mingw-w64 mingw-w64-tools
|
||||
- name: Install libusb
|
||||
env:
|
||||
LIBUSB_VERSION: 1.0.26
|
||||
run: |
|
||||
wget -c https://github.com/libusb/libusb/archive/refs/tags/v${LIBUSB_VERSION}.tar.gz
|
||||
tar xzf v${LIBUSB_VERSION}.tar.gz
|
||||
pushd libusb-${LIBUSB_VERSION}
|
||||
autoreconf --install --force
|
||||
./configure --host=${{ matrix.arch }}-w64-mingw32 --prefix=/usr
|
||||
make
|
||||
make install DESTDIR=$PWD/../artifacts
|
||||
popd
|
||||
- name: Install hidapi
|
||||
env:
|
||||
HIDAPI_VERSION: 0.12.0
|
||||
run: |
|
||||
wget -c https://github.com/libusb/hidapi/archive/refs/tags/hidapi-${HIDAPI_VERSION}.tar.gz
|
||||
tar xzf hidapi-${HIDAPI_VERSION}.tar.gz
|
||||
pushd hidapi-hidapi-${HIDAPI_VERSION}
|
||||
autoreconf --install --force
|
||||
./configure --host=${{ matrix.arch }}-w64-mingw32 --prefix=/usr LDFLAGS='-static-libgcc'
|
||||
make
|
||||
make install DESTDIR=$PWD/../artifacts
|
||||
popd
|
||||
- run: autoreconf --install --force
|
||||
- run: ./configure --host=${{ matrix.arch }}-w64-mingw32 --prefix=/usr
|
||||
env:
|
||||
PKG_CONFIG_LIBDIR: ${{ github.workspace }}/artifacts/usr/lib/pkgconfig
|
||||
PKG_CONFIG_SYSROOT_DIR: ${{ github.workspace }}/artifacts
|
||||
PKG_CONFIG_ALLOW_SYSTEM_CFLAGS: 1
|
||||
PKG_CONFIG_ALLOW_SYSTEM_LIBS: 1
|
||||
- run: make
|
||||
- run: make distcheck
|
||||
- name: Package artifacts
|
||||
run: |
|
||||
make install DESTDIR=$PWD/artifacts
|
||||
tar -czf ${{ github.job }}-${{ matrix.arch }}.tar.gz -C artifacts usr
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ github.job }}-${{ matrix.arch }}
|
||||
path: ${{ github.job }}-${{ matrix.arch }}.tar.gz
|
||||
|
||||
# msvc:
|
||||
#
|
||||
# name: Visual Studio
|
||||
#
|
||||
# runs-on: windows-latest
|
||||
#
|
||||
# strategy:
|
||||
# fail-fast: false
|
||||
# matrix:
|
||||
# platform: [x86, x64]
|
||||
#
|
||||
# env:
|
||||
# CONFIGURATION: Release
|
||||
#
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
# - uses: msys2/setup-msys2@v2
|
||||
# with:
|
||||
# install: autoconf automake libtool pkg-config make gcc
|
||||
# - run: |
|
||||
# autoreconf --install --force
|
||||
# ./configure --prefix=/usr
|
||||
# make -C src revision.h
|
||||
# shell: msys2 {0}
|
||||
# - uses: microsoft/setup-msbuild@v1
|
||||
# - run: msbuild -m -p:Platform=${{ matrix.platform }} -p:Configuration=${{ env.CONFIGURATION }} contrib/msvc/libdivecomputer.vcxproj
|
||||
# - uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: ${{ github.job }}-${{ matrix.platform }}
|
||||
# path: contrib/msvc/${{ matrix.platform }}/${{ env.CONFIGURATION }}/bin
|
||||
|
||||
android:
|
||||
|
||||
name: Android
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: |
|
||||
autoreconf --install --force
|
||||
./configure --prefix=/usr
|
||||
make -C src revision.h
|
||||
- run: $ANDROID_NDK/ndk-build -C contrib/android NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ github.job }}
|
||||
path: contrib/android/libs
|
||||
47
.github/workflows/release.yml
vendored
47
.github/workflows/release.yml
vendored
@ -1,47 +0,0 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: 'v*'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Version number
|
||||
id: version
|
||||
run: |
|
||||
VERSION="${GITHUB_REF/refs\/tags\/v/}"
|
||||
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build distribution tarball
|
||||
id: build
|
||||
run: |
|
||||
sudo apt-get install libbluetooth-dev libusb-1.0-0-dev
|
||||
autoreconf --install --force
|
||||
./configure
|
||||
make
|
||||
make distcheck
|
||||
|
||||
- name: Check tarball version number
|
||||
id: check
|
||||
run: |
|
||||
FILENAME="libdivecomputer-${{ steps.version.outputs.version }}.tar.gz"
|
||||
if [ ! -f "${FILENAME}" ]; then
|
||||
echo ::error ::Tarball \'${FILENAME}\' not found!
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Create Github release
|
||||
id: release
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
if [ "${VERSION}" != "${VERSION%%-*}" ]; then
|
||||
PRERELEASE="-p"
|
||||
fi
|
||||
gh release create ${PRERELEASE} "${{ github.ref }}" "libdivecomputer-${VERSION}.tar.gz"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@ -47,10 +47,11 @@ Makefile.in
|
||||
/m4/ltsugar.m4
|
||||
/m4/ltversion.m4
|
||||
|
||||
/msvc/x64/
|
||||
/msvc/x86/
|
||||
/msvc/Debug/
|
||||
/msvc/Release/
|
||||
/msvc/*.ncb
|
||||
/msvc/*.suo
|
||||
/msvc/*.vcproj.*.user
|
||||
|
||||
/src/libdivecomputer.exp
|
||||
/src/libdivecomputer.la
|
||||
|
||||
@ -16,8 +16,4 @@ pkgconfig_DATA = libdivecomputer.pc
|
||||
|
||||
EXTRA_DIST = \
|
||||
libdivecomputer.pc.in \
|
||||
contrib/README \
|
||||
contrib/android/Android.mk \
|
||||
contrib/msvc/libdivecomputer.vcxproj \
|
||||
contrib/msvc/libdivecomputer.vcxproj.filters \
|
||||
contrib/udev/libdivecomputer.rules
|
||||
msvc/libdivecomputer.vcproj
|
||||
|
||||
74
NEWS
74
NEWS
@ -1,77 +1,3 @@
|
||||
Version 0.8.0 (2023-05-11)
|
||||
==========================
|
||||
|
||||
The v0.8.0 release is mainly a bugfix release, and brings in support for a
|
||||
number of new devices. This release is fully backwards compatible with the
|
||||
previous one.
|
||||
|
||||
New features:
|
||||
|
||||
* Add support for new backends:
|
||||
- excursion: Deep Six Excursion, Crest CR-4, Genesis Centauri, Tusa TC1, Scorpena Alpha
|
||||
- screen: Seac Screen and Action
|
||||
- cosmiq: Deepblu Cosmiq+
|
||||
- s1: Oceans S1
|
||||
- freedom: Divesoft Freedom and Liberty
|
||||
* Add support for some new devices:
|
||||
- Aqualung: i200C
|
||||
- Cressi: Donatello, Michelangelo, Neon
|
||||
- Mares: Puck Pro +
|
||||
- Oceanic: Geo Air
|
||||
- Ratio: iX3M 2
|
||||
- Scubapro: G2 TEK
|
||||
- Shearwater: Petrel 3, Perdix 2
|
||||
- Sherwood: Amphos Air 2.0
|
||||
* Add support for parsing the decompression model
|
||||
* Add a public api to configure the depth calibration
|
||||
* Add a public api to configure the clock synchronization
|
||||
* Add a basic Android build system
|
||||
|
||||
Removed/changed features:
|
||||
|
||||
* Migrate to Visual Studio 2013 (or newer)
|
||||
* Move the Visual Studio project to the contrib directory
|
||||
|
||||
Version 0.7.0 (2021-05-07)
|
||||
==========================
|
||||
|
||||
The main highlight of the v0.7.0 release is the introduction of the new
|
||||
I/O interface. With this common interface, the dive computer backends
|
||||
can more easily use different I/O implementations at runtime, including
|
||||
an application defined one. This is needed to support Bluetooth Low
|
||||
Energy (BLE), for which there is no built-in implementation available.
|
||||
|
||||
Due to the fundamental changes to the I/O layer, this release is not
|
||||
backwards compatible.
|
||||
|
||||
New features:
|
||||
|
||||
* A new I/O interface
|
||||
* Add support for new backends:
|
||||
- goa: Cressi Goa and Cartesio
|
||||
- divecomputereu: Tecdiving DiveComputer.eu
|
||||
- extreme: McLean Extreme
|
||||
- lynx: Liquivision Xen, Xeo, Lynx and Kaon
|
||||
- sp2: Sporasub SP2
|
||||
* Add support for many new devices:
|
||||
- Aqualung: i100, i200C, i300C, i470TC, i550C, i770R
|
||||
- Heinrichs Weikamp: OSTC 2 TR
|
||||
- Mares: Genius, Horizon, Quad Air, Smart Air
|
||||
- Oceanic: Geo 4.0, Pro Plus 4, Pro Plus X, Veo 4.0
|
||||
- Ratio: iDive Color, iX3M GPS, iX3M 2021
|
||||
- Scubapro: A1, A2, Aladin H Matrix, G2 Console, G2 HUD
|
||||
- Seac: Guru, Jack
|
||||
- Shearwater: Peregrine, Teric
|
||||
- Sherwood: Amphos 2.0, Beacon, Sage, Wisdom 4
|
||||
- Suunto: D5, EON Steel Black
|
||||
- Tusa: Talis
|
||||
* Firmware upgrade support for the Ratio computers
|
||||
* Support for semi-closed circuit diving
|
||||
|
||||
Removed/changed features:
|
||||
|
||||
* Unify the Uwatec Smart, Meridian and G2 backends
|
||||
|
||||
Version 0.6.0 (2017-11-24)
|
||||
==========================
|
||||
|
||||
|
||||
84
configure.ac
84
configure.ac
@ -1,6 +1,6 @@
|
||||
# Versioning.
|
||||
m4_define([dc_version_major],[0])
|
||||
m4_define([dc_version_minor],[9])
|
||||
m4_define([dc_version_minor],[7])
|
||||
m4_define([dc_version_micro],[0])
|
||||
m4_define([dc_version_suffix],[devel-Subsurface-NG])
|
||||
m4_define([dc_version],dc_version_major.dc_version_minor.dc_version_micro[]m4_ifset([dc_version_suffix],-[dc_version_suffix]))
|
||||
@ -72,21 +72,18 @@ AM_CONDITIONAL([HAVE_MANDOC],[test -n "$MANDOC"])
|
||||
# Enable automake silent build rules.
|
||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
||||
|
||||
# Checks for operating system.
|
||||
AC_MSG_CHECKING([for operating system])
|
||||
# Checks for native Windows.
|
||||
AC_MSG_CHECKING([for native Win32])
|
||||
case "$host" in
|
||||
*-*-mingw*)
|
||||
platform=windows
|
||||
;;
|
||||
*-*-darwin*)
|
||||
platform=mac
|
||||
os_win32=yes
|
||||
;;
|
||||
*)
|
||||
platform=default
|
||||
os_win32=no
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT([$platform])
|
||||
AM_CONDITIONAL([OS_WIN32], [test "$platform" = "windows"])
|
||||
AC_MSG_RESULT([$os_win32])
|
||||
AM_CONDITIONAL([OS_WIN32], [test "$os_win32" = "yes"])
|
||||
|
||||
DEPENDENCIES=""
|
||||
|
||||
@ -120,12 +117,12 @@ AS_IF([test "x$with_libmtp" != "xno"], [
|
||||
AC_ARG_WITH([hidapi],
|
||||
[AS_HELP_STRING([--without-hidapi],
|
||||
[Build without the hidapi library])],
|
||||
[], [with_hidapi=hidapi])
|
||||
[], [with_hidapi=auto])
|
||||
AS_IF([test "x$with_hidapi" != "xno"], [
|
||||
PKG_CHECK_MODULES([HIDAPI], [$with_hidapi], [have_hidapi=yes], [have_hidapi=no])
|
||||
PKG_CHECK_MODULES([HIDAPI], [hidapi], [have_hidapi=yes], [have_hidapi=no])
|
||||
AS_IF([test "x$have_hidapi" = "xyes"], [
|
||||
AC_DEFINE([HAVE_HIDAPI], [1], [hidapi library])
|
||||
DEPENDENCIES="$DEPENDENCIES $with_hidapi"
|
||||
DEPENDENCIES="$DEPENDENCIES hidapi"
|
||||
])
|
||||
])
|
||||
|
||||
@ -170,7 +167,7 @@ AC_CHECK_HEADERS([sys/socket.h linux/types.h linux/irda.h], , , [
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS([linux/serial.h])
|
||||
AC_CHECK_HEADERS([IOKit/serial/ioss.h])
|
||||
AC_CHECK_HEADERS([unistd.h getopt.h])
|
||||
AC_CHECK_HEADERS([getopt.h])
|
||||
AC_CHECK_HEADERS([sys/param.h])
|
||||
AC_CHECK_HEADERS([pthread.h])
|
||||
AC_CHECK_HEADERS([mach/mach_time.h])
|
||||
@ -190,7 +187,6 @@ AC_CHECK_FUNCS([clock_gettime mach_absolute_time])
|
||||
AC_CHECK_FUNCS([getopt_long])
|
||||
|
||||
# Checks for supported compiler options.
|
||||
AX_APPEND_COMPILE_FLAGS([-Werror=unknown-warning-option],[ERROR_CFLAGS])
|
||||
AX_APPEND_COMPILE_FLAGS([ \
|
||||
-Wall \
|
||||
-Wshadow \
|
||||
@ -207,13 +203,11 @@ AX_APPEND_COMPILE_FLAGS([ \
|
||||
-Wno-unused-but-set-variable \
|
||||
-Wno-pointer-sign \
|
||||
-Wno-shadow \
|
||||
-Wenum-conversion \
|
||||
-Werror=enum-conversion \
|
||||
-fmacro-prefix-map='$(top_srcdir)/'= \
|
||||
],,[$ERROR_CFLAGS])
|
||||
])
|
||||
|
||||
# Windows specific compiler options.
|
||||
AS_IF([test "$platform" = "windows"], [
|
||||
AS_IF([test "$os_win32" = "yes"], [
|
||||
AX_APPEND_COMPILE_FLAGS([-Wno-pedantic-ms-format])
|
||||
])
|
||||
|
||||
@ -229,25 +223,6 @@ m4_ifset([dc_version_suffix],[
|
||||
AC_DEFINE(HAVE_VERSION_SUFFIX, [1], [Define if a version suffix is present.])
|
||||
])
|
||||
|
||||
# Supported transports
|
||||
transport_serial="yes"
|
||||
transport_usb="${have_libusb-no}"
|
||||
if test "$have_hidapi" = "yes"; then
|
||||
transport_usbhid="yes"
|
||||
elif test "$have_libusb" = "yes" && test "$platform" != "mac"; then
|
||||
transport_usbhid="yes"
|
||||
else
|
||||
transport_usbhid="no"
|
||||
fi
|
||||
if test "$platform" = "windows"; then
|
||||
transport_irda="$ac_cv_header_af_irda_h"
|
||||
transport_bluetooth="$ac_cv_header_ws2bth_h"
|
||||
else
|
||||
transport_irda="$ac_cv_header_linux_irda_h"
|
||||
transport_bluetooth="${have_bluez-no}"
|
||||
fi
|
||||
transport_ble="no"
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
libdivecomputer.pc
|
||||
Makefile
|
||||
@ -255,41 +230,10 @@ AC_CONFIG_FILES([
|
||||
include/libdivecomputer/Makefile
|
||||
include/libdivecomputer/version.h
|
||||
src/Makefile
|
||||
src/libdivecomputer.rc
|
||||
doc/Makefile
|
||||
doc/doxygen.cfg
|
||||
doc/man/Makefile
|
||||
examples/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
AC_MSG_NOTICE([
|
||||
$PACKAGE $VERSION
|
||||
===============
|
||||
|
||||
Compiler:
|
||||
|
||||
CC : $CC
|
||||
CFLAGS : $CFLAGS
|
||||
LDFLAGS : $LDFLAGS
|
||||
|
||||
Features:
|
||||
|
||||
Logging : $enable_logging
|
||||
Pseudo terminal : $enable_pty
|
||||
Example applications : $enable_examples
|
||||
Documentation : $enable_doc
|
||||
|
||||
Transports:
|
||||
|
||||
Serial : $transport_serial
|
||||
USB : $transport_usb
|
||||
USBHID : $transport_usbhid
|
||||
IrDA : $transport_irda
|
||||
Bluetooth : $transport_bluetooth
|
||||
BLE : $transport_ble
|
||||
|
||||
Building:
|
||||
|
||||
Type 'make' to compile $PACKAGE.
|
||||
|
||||
Type 'make install' to install $PACKAGE.
|
||||
])
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
Alternative build systems
|
||||
=========================
|
||||
|
||||
The autotools based build system is the official build system for the
|
||||
libdivecomputer project. But for convenience, a few alternative build systems
|
||||
are available as well. Unfortunately, these builds systems require a few extra
|
||||
steps to generate some header files.
|
||||
|
||||
If you have access to a UNIX build system (for example a Linux virtual machine,
|
||||
MinGW, Cygwin or the Windows Subsystem for Linux), you can use the autotools
|
||||
build system to generate those files:
|
||||
|
||||
$ autoreconf --install --force
|
||||
$ ./configure
|
||||
$ make -C src revision.h
|
||||
|
||||
Alternative, you can generate those files manually. First, create the version.h
|
||||
file from the version.h.in template:
|
||||
|
||||
$ cp include/libdivecomputer/version.h.in include/libdivecomputer/version.h
|
||||
|
||||
and replace all the @DC_VERSION@ placeholders with the values defined in the
|
||||
configure.ac file.
|
||||
|
||||
Next, generate the revision.h file:
|
||||
|
||||
$ echo "#define DC_VERSION_REVISION \"$(git rev-parse --verify HEAD)\"" > src/revision.h
|
||||
|
||||
The alternative build systems are ready to use now.
|
||||
|
||||
Visual Studio
|
||||
-------------
|
||||
|
||||
The Visual Studio project file can be opened in the IDE, or build directly from
|
||||
the command-line:
|
||||
|
||||
msbuild -m -p:Platform=x86|x64 -p:Configuration=Debug|Release contrib/msvc/libdivecomputer.vcxproj
|
||||
|
||||
Android NDK
|
||||
-----------
|
||||
|
||||
$ANDROID_NDK/ndk-build -C contrib/android NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk
|
||||
|
||||
Linux udev rules
|
||||
================
|
||||
|
||||
For dive computers using USB or USB HID communication, regular users typically
|
||||
don't have the necessary permissions to access the device nodes. This can be
|
||||
fixed with some udev rules.
|
||||
|
||||
Install the udev rules, and reload them:
|
||||
|
||||
$ sudo cp contrib/udev/libdivecomputer.rules /etc/udev/rules.d/
|
||||
$ sudo udevadm control --reload
|
||||
|
||||
Note: the provided udev rules assume the user is in the plugdev group.
|
||||
@ -1,148 +0,0 @@
|
||||
LOCAL_PATH := $(call my-dir)/../..
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := libdivecomputer
|
||||
LOCAL_CFLAGS := -DENABLE_LOGGING -DHAVE_VERSION_SUFFIX -DHAVE_PTHREAD_H -DHAVE_STRERROR_R -DHAVE_CLOCK_GETTIME -DHAVE_LOCALTIME_R -DHAVE_GMTIME_R -DHAVE_TIMEGM -DHAVE_STRUCT_TM_TM_GMTOFF
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
|
||||
LOCAL_SRC_FILES := \
|
||||
src/aes.c \
|
||||
src/array.c \
|
||||
src/atomics_cobalt.c \
|
||||
src/atomics_cobalt_parser.c \
|
||||
src/bluetooth.c \
|
||||
src/buffer.c \
|
||||
src/checksum.c \
|
||||
src/citizen_aqualand.c \
|
||||
src/citizen_aqualand_parser.c \
|
||||
src/cochran_commander.c \
|
||||
src/cochran_commander_parser.c \
|
||||
src/common.c \
|
||||
src/context.c \
|
||||
src/cressi_edy.c \
|
||||
src/cressi_edy_parser.c \
|
||||
src/cressi_goa.c \
|
||||
src/cressi_goa_parser.c \
|
||||
src/cressi_leonardo.c \
|
||||
src/cressi_leonardo_parser.c \
|
||||
src/custom.c \
|
||||
src/datetime.c \
|
||||
src/deepblu_cosmiq.c \
|
||||
src/deepblu_cosmiq_parser.c \
|
||||
src/deepsix_excursion.c \
|
||||
src/deepsix_excursion_parser.c \
|
||||
src/descriptor.c \
|
||||
src/device.c \
|
||||
src/diverite_nitekq.c \
|
||||
src/diverite_nitekq_parser.c \
|
||||
src/divesoft_freedom.c \
|
||||
src/divesoft_freedom_parser.c \
|
||||
src/divesystem_idive.c \
|
||||
src/divesystem_idive_parser.c \
|
||||
src/hdlc.c \
|
||||
src/hw_frog.c \
|
||||
src/hw_ostc3.c \
|
||||
src/hw_ostc.c \
|
||||
src/hw_ostc_parser.c \
|
||||
src/ihex.c \
|
||||
src/iostream.c \
|
||||
src/irda.c \
|
||||
src/iterator.c \
|
||||
src/liquivision_lynx.c \
|
||||
src/liquivision_lynx_parser.c \
|
||||
src/mares_common.c \
|
||||
src/mares_darwin.c \
|
||||
src/mares_darwin_parser.c \
|
||||
src/mares_iconhd.c \
|
||||
src/mares_iconhd_parser.c \
|
||||
src/mares_nemo.c \
|
||||
src/mares_nemo_parser.c \
|
||||
src/mares_puck.c \
|
||||
src/mclean_extreme.c \
|
||||
src/mclean_extreme_parser.c \
|
||||
src/oceanic_atom2.c \
|
||||
src/oceanic_atom2_parser.c \
|
||||
src/oceanic_common.c \
|
||||
src/oceanic_veo250.c \
|
||||
src/oceanic_veo250_parser.c \
|
||||
src/oceanic_vtpro.c \
|
||||
src/oceanic_vtpro_parser.c \
|
||||
src/oceans_s1.c \
|
||||
src/oceans_s1_common.c \
|
||||
src/oceans_s1_parser.c \
|
||||
src/packet.c \
|
||||
src/parser.c \
|
||||
src/pelagic_i330r.c \
|
||||
src/platform.c \
|
||||
src/rbstream.c \
|
||||
src/reefnet_sensus.c \
|
||||
src/reefnet_sensus_parser.c \
|
||||
src/reefnet_sensuspro.c \
|
||||
src/reefnet_sensuspro_parser.c \
|
||||
src/reefnet_sensusultra.c \
|
||||
src/reefnet_sensusultra_parser.c \
|
||||
src/ringbuffer.c \
|
||||
src/seac_screen.c \
|
||||
src/seac_screen_parser.c \
|
||||
src/serial_posix.c \
|
||||
src/shearwater_common.c \
|
||||
src/shearwater_petrel.c \
|
||||
src/shearwater_predator.c \
|
||||
src/shearwater_predator_parser.c \
|
||||
src/socket.c \
|
||||
src/sporasub_sp2.c \
|
||||
src/sporasub_sp2_parser.c \
|
||||
src/suunto_common2.c \
|
||||
src/suunto_common.c \
|
||||
src/suunto_d9.c \
|
||||
src/suunto_d9_parser.c \
|
||||
src/suunto_eon.c \
|
||||
src/suunto_eon_parser.c \
|
||||
src/suunto_eonsteel.c \
|
||||
src/suunto_eonsteel_parser.c \
|
||||
src/suunto_solution.c \
|
||||
src/suunto_solution_parser.c \
|
||||
src/suunto_vyper2.c \
|
||||
src/suunto_vyper.c \
|
||||
src/suunto_vyper_parser.c \
|
||||
src/tecdiving_divecomputereu.c \
|
||||
src/tecdiving_divecomputereu_parser.c \
|
||||
src/timer.c \
|
||||
src/usb.c \
|
||||
src/usbhid.c \
|
||||
src/uwatec_aladin.c \
|
||||
src/uwatec_memomouse.c \
|
||||
src/uwatec_memomouse_parser.c \
|
||||
src/uwatec_smart.c \
|
||||
src/uwatec_smart_parser.c \
|
||||
src/version.c \
|
||||
src/zeagle_n2ition3.c \
|
||||
src/field-cache.c \
|
||||
src/usb_storage.c \
|
||||
src/garmin.c \
|
||||
src/garmin_parser.c
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := dctool
|
||||
LOCAL_SHARED_LIBRARIES := libdivecomputer
|
||||
LOCAL_CFLAGS := -DHAVE_UNISTD_H -DHAVE_GETOPT_H -DHAVE_GETOPT_LONG -DHAVE_DECL_OPTRESET=1
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
|
||||
LOCAL_SRC_FILES := \
|
||||
examples/common.c \
|
||||
examples/dctool.c \
|
||||
examples/dctool_download.c \
|
||||
examples/dctool_dump.c \
|
||||
examples/dctool_fwupdate.c \
|
||||
examples/dctool_help.c \
|
||||
examples/dctool_list.c \
|
||||
examples/dctool_parse.c \
|
||||
examples/dctool_read.c \
|
||||
examples/dctool_scan.c \
|
||||
examples/dctool_timesync.c \
|
||||
examples/dctool_version.c \
|
||||
examples/dctool_write.c \
|
||||
examples/output.c \
|
||||
examples/output_raw.c \
|
||||
examples/output_xml.c \
|
||||
examples/utils.c
|
||||
include $(BUILD_EXECUTABLE)
|
||||
@ -1,408 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{CEA7215A-D6B5-4840-8086-3C854F371997}</ProjectGuid>
|
||||
<RootNamespace>libdivecomputer</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(PlatformTarget)\$(Configuration)\bin\</OutDir>
|
||||
<IntDir>$(PlatformTarget)\$(Configuration)\obj\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(PlatformTarget)\$(Configuration)\bin\</OutDir>
|
||||
<IntDir>$(PlatformTarget)\$(Configuration)\obj\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(PlatformTarget)\$(Configuration)\bin\</OutDir>
|
||||
<IntDir>$(PlatformTarget)\$(Configuration)\obj\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(PlatformTarget)\$(Configuration)\bin\</OutDir>
|
||||
<IntDir>$(PlatformTarget)\$(Configuration)\obj\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_VERSION_SUFFIX;HAVE_AF_IRDA_H;HAVE_WS2BTH_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader />
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>$(OutDir)libdivecomputer.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_VERSION_SUFFIX;HAVE_AF_IRDA_H;HAVE_WS2BTH_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>$(OutDir)libdivecomputer.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_VERSION_SUFFIX;HAVE_AF_IRDA_H;HAVE_WS2BTH_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader />
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>$(OutDir)libdivecomputer.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
</Link>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_VERSION_SUFFIX;HAVE_AF_IRDA_H;HAVE_WS2BTH_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>$(OutDir)libdivecomputer.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
</Link>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\aes.c" />
|
||||
<ClCompile Include="..\..\src\array.c" />
|
||||
<ClCompile Include="..\..\src\atomics_cobalt.c" />
|
||||
<ClCompile Include="..\..\src\atomics_cobalt_parser.c" />
|
||||
<ClCompile Include="..\..\src\bluetooth.c" />
|
||||
<ClCompile Include="..\..\src\buffer.c" />
|
||||
<ClCompile Include="..\..\src\checksum.c" />
|
||||
<ClCompile Include="..\..\src\citizen_aqualand.c" />
|
||||
<ClCompile Include="..\..\src\citizen_aqualand_parser.c" />
|
||||
<ClCompile Include="..\..\src\cochran_commander.c" />
|
||||
<ClCompile Include="..\..\src\cochran_commander_parser.c" />
|
||||
<ClCompile Include="..\..\src\common.c" />
|
||||
<ClCompile Include="..\..\src\context.c" />
|
||||
<ClCompile Include="..\..\src\cressi_edy.c" />
|
||||
<ClCompile Include="..\..\src\cressi_edy_parser.c" />
|
||||
<ClCompile Include="..\..\src\cressi_goa.c" />
|
||||
<ClCompile Include="..\..\src\cressi_goa_parser.c" />
|
||||
<ClCompile Include="..\..\src\cressi_leonardo.c" />
|
||||
<ClCompile Include="..\..\src\cressi_leonardo_parser.c" />
|
||||
<ClCompile Include="..\..\src\custom.c" />
|
||||
<ClCompile Include="..\..\src\datetime.c" />
|
||||
<ClCompile Include="..\..\src\deepblu_cosmiq.c" />
|
||||
<ClCompile Include="..\..\src\deepblu_cosmiq_parser.c" />
|
||||
<ClCompile Include="..\..\src\deepsix_excursion.c" />
|
||||
<ClCompile Include="..\..\src\deepsix_excursion_parser.c" />
|
||||
<ClCompile Include="..\..\src\descriptor.c" />
|
||||
<ClCompile Include="..\..\src\device.c" />
|
||||
<ClCompile Include="..\..\src\diverite_nitekq.c" />
|
||||
<ClCompile Include="..\..\src\diverite_nitekq_parser.c" />
|
||||
<ClCompile Include="..\..\src\divesoft_freedom.c" />
|
||||
<ClCompile Include="..\..\src\divesoft_freedom_parser.c" />
|
||||
<ClCompile Include="..\..\src\divesystem_idive.c" />
|
||||
<ClCompile Include="..\..\src\divesystem_idive_parser.c" />
|
||||
<ClCompile Include="..\..\src\hdlc.c" />
|
||||
<ClCompile Include="..\..\src\hw_frog.c" />
|
||||
<ClCompile Include="..\..\src\hw_ostc.c" />
|
||||
<ClCompile Include="..\..\src\hw_ostc3.c" />
|
||||
<ClCompile Include="..\..\src\hw_ostc_parser.c" />
|
||||
<ClCompile Include="..\..\src\ihex.c" />
|
||||
<ClCompile Include="..\..\src\iostream.c" />
|
||||
<ClCompile Include="..\..\src\irda.c" />
|
||||
<ClCompile Include="..\..\src\iterator.c" />
|
||||
<ClCompile Include="..\..\src\liquivision_lynx.c" />
|
||||
<ClCompile Include="..\..\src\liquivision_lynx_parser.c" />
|
||||
<ClCompile Include="..\..\src\mares_common.c" />
|
||||
<ClCompile Include="..\..\src\mares_darwin.c" />
|
||||
<ClCompile Include="..\..\src\mares_darwin_parser.c" />
|
||||
<ClCompile Include="..\..\src\mares_iconhd.c" />
|
||||
<ClCompile Include="..\..\src\mares_iconhd_parser.c" />
|
||||
<ClCompile Include="..\..\src\mares_nemo.c" />
|
||||
<ClCompile Include="..\..\src\mares_nemo_parser.c" />
|
||||
<ClCompile Include="..\..\src\mares_puck.c" />
|
||||
<ClCompile Include="..\..\src\mclean_extreme.c" />
|
||||
<ClCompile Include="..\..\src\mclean_extreme_parser.c" />
|
||||
<ClCompile Include="..\..\src\oceanic_atom2.c" />
|
||||
<ClCompile Include="..\..\src\oceanic_atom2_parser.c" />
|
||||
<ClCompile Include="..\..\src\oceanic_common.c" />
|
||||
<ClCompile Include="..\..\src\oceanic_veo250.c" />
|
||||
<ClCompile Include="..\..\src\oceanic_veo250_parser.c" />
|
||||
<ClCompile Include="..\..\src\oceanic_vtpro.c" />
|
||||
<ClCompile Include="..\..\src\oceanic_vtpro_parser.c" />
|
||||
<ClCompile Include="..\..\src\oceans_s1.c" />
|
||||
<ClCompile Include="..\..\src\oceans_s1_common.c" />
|
||||
<ClCompile Include="..\..\src\oceans_s1_parser.c" />
|
||||
<ClCompile Include="..\..\src\packet.c" />
|
||||
<ClCompile Include="..\..\src\parser.c" />
|
||||
<ClCompile Include="..\..\src\pelagic_i330r.c" />
|
||||
<ClCompile Include="..\..\src\platform.c" />
|
||||
<ClCompile Include="..\..\src\rbstream.c" />
|
||||
<ClCompile Include="..\..\src\reefnet_sensus.c" />
|
||||
<ClCompile Include="..\..\src\reefnet_sensuspro.c" />
|
||||
<ClCompile Include="..\..\src\reefnet_sensuspro_parser.c" />
|
||||
<ClCompile Include="..\..\src\reefnet_sensusultra.c" />
|
||||
<ClCompile Include="..\..\src\reefnet_sensusultra_parser.c" />
|
||||
<ClCompile Include="..\..\src\reefnet_sensus_parser.c" />
|
||||
<ClCompile Include="..\..\src\ringbuffer.c" />
|
||||
<ClCompile Include="..\..\src\seac_screen.c" />
|
||||
<ClCompile Include="..\..\src\seac_screen_parser.c" />
|
||||
<ClCompile Include="..\..\src\serial_win32.c" />
|
||||
<ClCompile Include="..\..\src\shearwater_common.c" />
|
||||
<ClCompile Include="..\..\src\shearwater_petrel.c" />
|
||||
<ClCompile Include="..\..\src\shearwater_predator.c" />
|
||||
<ClCompile Include="..\..\src\shearwater_predator_parser.c" />
|
||||
<ClCompile Include="..\..\src\socket.c" />
|
||||
<ClCompile Include="..\..\src\sporasub_sp2.c" />
|
||||
<ClCompile Include="..\..\src\sporasub_sp2_parser.c" />
|
||||
<ClCompile Include="..\..\src\suunto_common.c" />
|
||||
<ClCompile Include="..\..\src\suunto_common2.c" />
|
||||
<ClCompile Include="..\..\src\suunto_d9.c" />
|
||||
<ClCompile Include="..\..\src\suunto_d9_parser.c" />
|
||||
<ClCompile Include="..\..\src\suunto_eon.c" />
|
||||
<ClCompile Include="..\..\src\suunto_eonsteel.c" />
|
||||
<ClCompile Include="..\..\src\suunto_eonsteel_parser.c" />
|
||||
<ClCompile Include="..\..\src\suunto_eon_parser.c" />
|
||||
<ClCompile Include="..\..\src\suunto_solution.c" />
|
||||
<ClCompile Include="..\..\src\suunto_solution_parser.c" />
|
||||
<ClCompile Include="..\..\src\suunto_vyper.c" />
|
||||
<ClCompile Include="..\..\src\suunto_vyper2.c" />
|
||||
<ClCompile Include="..\..\src\suunto_vyper_parser.c" />
|
||||
<ClCompile Include="..\..\src\tecdiving_divecomputereu.c" />
|
||||
<ClCompile Include="..\..\src\tecdiving_divecomputereu_parser.c" />
|
||||
<ClCompile Include="..\..\src\timer.c" />
|
||||
<ClCompile Include="..\..\src\usb.c" />
|
||||
<ClCompile Include="..\..\src\usbhid.c" />
|
||||
<ClCompile Include="..\..\src\uwatec_aladin.c" />
|
||||
<ClCompile Include="..\..\src\uwatec_memomouse.c" />
|
||||
<ClCompile Include="..\..\src\uwatec_memomouse_parser.c" />
|
||||
<ClCompile Include="..\..\src\uwatec_smart.c" />
|
||||
<ClCompile Include="..\..\src\uwatec_smart_parser.c" />
|
||||
<ClCompile Include="..\..\src\version.c" />
|
||||
<ClCompile Include="..\..\src\zeagle_n2ition3.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\include\libdivecomputer\atomics_cobalt.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\ble.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\bluetooth.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\buffer.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\common.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\context.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\custom.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\datetime.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\descriptor.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\device.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\divesystem_idive.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\hw_frog.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\hw_ostc.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\hw_ostc3.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\ioctl.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\iostream.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\irda.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\iterator.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\oceanic_atom2.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\oceanic_veo250.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\oceanic_vtpro.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\parser.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\reefnet_sensus.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\reefnet_sensuspro.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\reefnet_sensusultra.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\serial.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\suunto_d9.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\suunto_eon.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\suunto_vyper2.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\units.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\usb.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\usbhid.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\version.h" />
|
||||
<ClInclude Include="..\..\src\aes.h" />
|
||||
<ClInclude Include="..\..\src\array.h" />
|
||||
<ClInclude Include="..\..\src\atomics_cobalt.h" />
|
||||
<ClInclude Include="..\..\src\checksum.h" />
|
||||
<ClInclude Include="..\..\src\citizen_aqualand.h" />
|
||||
<ClInclude Include="..\..\src\cochran_commander.h" />
|
||||
<ClInclude Include="..\..\src\common-private.h" />
|
||||
<ClInclude Include="..\..\src\context-private.h" />
|
||||
<ClInclude Include="..\..\src\cressi_edy.h" />
|
||||
<ClInclude Include="..\..\src\cressi_goa.h" />
|
||||
<ClInclude Include="..\..\src\cressi_leonardo.h" />
|
||||
<ClInclude Include="..\..\src\deepblu_cosmiq.h" />
|
||||
<ClInclude Include="..\..\src\deepsix_excursion.h" />
|
||||
<ClInclude Include="..\..\src\device-private.h" />
|
||||
<ClInclude Include="..\..\src\diverite_nitekq.h" />
|
||||
<ClInclude Include="..\..\src\divesoft_freedom.h" />
|
||||
<ClInclude Include="..\..\src\divesystem_idive.h" />
|
||||
<ClInclude Include="..\..\src\hdlc.h" />
|
||||
<ClInclude Include="..\..\src\hw_frog.h" />
|
||||
<ClInclude Include="..\..\src\hw_ostc.h" />
|
||||
<ClInclude Include="..\..\src\hw_ostc3.h" />
|
||||
<ClInclude Include="..\..\src\ihex.h" />
|
||||
<ClInclude Include="..\..\src\iostream-private.h" />
|
||||
<ClInclude Include="..\..\src\iterator-private.h" />
|
||||
<ClInclude Include="..\..\src\liquivision_lynx.h" />
|
||||
<ClInclude Include="..\..\src\mares_common.h" />
|
||||
<ClInclude Include="..\..\src\mares_darwin.h" />
|
||||
<ClInclude Include="..\..\src\mares_iconhd.h" />
|
||||
<ClInclude Include="..\..\src\mares_nemo.h" />
|
||||
<ClInclude Include="..\..\src\mares_puck.h" />
|
||||
<ClInclude Include="..\..\src\mclean_extreme.h" />
|
||||
<ClInclude Include="..\..\src\oceanic_atom2.h" />
|
||||
<ClInclude Include="..\..\src\oceanic_common.h" />
|
||||
<ClInclude Include="..\..\src\oceanic_veo250.h" />
|
||||
<ClInclude Include="..\..\src\oceanic_vtpro.h" />
|
||||
<ClInclude Include="..\..\src\oceans_s1.h" />
|
||||
<ClInclude Include="..\..\src\oceans_s1_common.h" />
|
||||
<ClInclude Include="..\..\src\packet.h" />
|
||||
<ClInclude Include="..\..\src\parser-private.h" />
|
||||
<ClInclude Include="..\..\src\pelagic_i330r.h" />
|
||||
<ClInclude Include="..\..\src\platform.h" />
|
||||
<ClInclude Include="..\..\src\rbstream.h" />
|
||||
<ClInclude Include="..\..\src\reefnet_sensus.h" />
|
||||
<ClInclude Include="..\..\src\reefnet_sensuspro.h" />
|
||||
<ClInclude Include="..\..\src\reefnet_sensusultra.h" />
|
||||
<ClInclude Include="..\..\src\revision.h" />
|
||||
<ClInclude Include="..\..\src\ringbuffer.h" />
|
||||
<ClInclude Include="..\..\src\seac_screen.h" />
|
||||
<ClInclude Include="..\..\src\shearwater_common.h" />
|
||||
<ClInclude Include="..\..\src\shearwater_petrel.h" />
|
||||
<ClInclude Include="..\..\src\shearwater_predator.h" />
|
||||
<ClInclude Include="..\..\src\socket.h" />
|
||||
<ClInclude Include="..\..\src\sporasub_sp2.h" />
|
||||
<ClInclude Include="..\..\src\suunto_common.h" />
|
||||
<ClInclude Include="..\..\src\suunto_common2.h" />
|
||||
<ClInclude Include="..\..\src\suunto_d9.h" />
|
||||
<ClInclude Include="..\..\src\suunto_eon.h" />
|
||||
<ClInclude Include="..\..\src\suunto_eonsteel.h" />
|
||||
<ClInclude Include="..\..\src\suunto_solution.h" />
|
||||
<ClInclude Include="..\..\src\suunto_vyper.h" />
|
||||
<ClInclude Include="..\..\src\suunto_vyper2.h" />
|
||||
<ClInclude Include="..\..\src\tecdiving_divecomputereu.h" />
|
||||
<ClInclude Include="..\..\src\timer.h" />
|
||||
<ClInclude Include="..\..\src\uwatec_aladin.h" />
|
||||
<ClInclude Include="..\..\src\uwatec_memomouse.h" />
|
||||
<ClInclude Include="..\..\src\uwatec_smart.h" />
|
||||
<ClInclude Include="..\..\src\zeagle_n2ition3.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\..\src\libdivecomputer.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\src\libdivecomputer.symbols">
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">echo EXPORTS > "$(OutDir)libdivecomputer.def" && type "%(FullPath)" >> "$(OutDir)libdivecomputer.def"</Command>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">echo EXPORTS > "$(OutDir)libdivecomputer.def" && type "%(FullPath)" >> "$(OutDir)libdivecomputer.def"</Command>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)libdivecomputer.def;%(Outputs)</Outputs>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)libdivecomputer.def;%(Outputs)</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">echo EXPORTS > "$(OutDir)libdivecomputer.def" && type "%(FullPath)" >> "$(OutDir)libdivecomputer.def"</Command>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">echo EXPORTS > "$(OutDir)libdivecomputer.def" && type "%(FullPath)" >> "$(OutDir)libdivecomputer.def"</Command>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)libdivecomputer.def;%(Outputs)</Outputs>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)libdivecomputer.def;%(Outputs)</Outputs>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@ -1,35 +1,23 @@
|
||||
# Atomic Aquatics Cobalt
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="0471", ATTR{idProduct}=="0888", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0471", ATTRS{idProduct}=="0888", GROUP="plugdev"
|
||||
|
||||
# Suunto EON Steel
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0030", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0030", GROUP="plugdev"
|
||||
|
||||
# Suunto EON Core
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0033", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0033", GROUP="plugdev"
|
||||
|
||||
# Suunto D5
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0035", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0035", GROUP="plugdev"
|
||||
|
||||
# Suunto EON Steel Black
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0036", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0036", GROUP="plugdev"
|
||||
|
||||
# Scubapro G2
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3201", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2e6c", ATTRS{idProduct}=="3201", GROUP="plugdev"
|
||||
|
||||
# Scubapro G2 Console
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3211", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2e6c", ATTRS{idProduct}=="3211", GROUP="plugdev"
|
||||
|
||||
# Scubapro G2 HUD
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="4201", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2e6c", ATTRS{idProduct}=="4201", GROUP="plugdev"
|
||||
|
||||
# Scubapro Aladin Square
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="c251", ATTR{idProduct}=="2006", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2006", GROUP="plugdev"
|
||||
|
||||
@ -32,6 +32,7 @@ MANPAGES = \
|
||||
dc_parser_get_field.3 \
|
||||
dc_parser_new.3 \
|
||||
dc_parser_samples_foreach.3 \
|
||||
dc_parser_set_data.3 \
|
||||
dc_bluetooth_open.3 \
|
||||
dc_bluetooth_iterator_new.3 \
|
||||
dc_bluetooth_device_get_address.3 \
|
||||
|
||||
@ -82,7 +82,7 @@ is
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_datetime_localtime 3 ,
|
||||
.Xr dc_datetime_mktime 3 ,
|
||||
.Xr dc_datetime_now 3
|
||||
.Xr dc_datetime_new 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -82,7 +82,7 @@ is
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_datetime_gmtime 3 ,
|
||||
.Xr dc_datetime_mktime 3 ,
|
||||
.Xr dc_datetime_now 3
|
||||
.Xr dc_datetime_new 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -47,7 +47,7 @@ may not sanely be converted.
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_datetime_gmtime 3 ,
|
||||
.Xr dc_datetime_localtime 3 ,
|
||||
.Xr dc_datetime_now 3
|
||||
.Xr dc_datetime_new 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -53,7 +53,7 @@ with
|
||||
Each dive invokes
|
||||
.Fa callback
|
||||
with the dive data, which should be parsed with
|
||||
.Xr dc_parser_new 3 ,
|
||||
.Xr dc_parser_set_data 3 ,
|
||||
and the binary fingerprint of the dive.
|
||||
The fingerprint can be used to record the newest dive and stop
|
||||
processing (on subsequent invocations) when the same dive fingerprint is
|
||||
@ -72,7 +72,7 @@ If
|
||||
returns zero, this will not be reflected in the return value (usually
|
||||
.Dv DC_STATUS_SUCCESS ) .
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_parser_new 3
|
||||
.Xr dc_parser_set_data 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
Extract the date and time of a dive,
|
||||
.Fa parser ,
|
||||
previously initialised with
|
||||
.Xr dc_parser_new 3 .
|
||||
.Xr dc_parser_set_data 3 .
|
||||
This returns the broken-down time-stamp of the dive in the local time of
|
||||
the dive.
|
||||
.Pp
|
||||
@ -57,7 +57,7 @@ messages on further failure.
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_datetime_gmtime 3 ,
|
||||
.Xr dc_datetime_localtime 3 ,
|
||||
.Xr dc_parser_new 3
|
||||
.Xr dc_parser_set_data 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
Extract a field from a dive,
|
||||
.Fa parser ,
|
||||
previously initialised with
|
||||
.Xr dc_parser_new 3 .
|
||||
.Xr dc_parser_set_data 3 .
|
||||
The
|
||||
.Fa value
|
||||
field type depends upon the
|
||||
@ -187,7 +187,7 @@ if the field was retrieved,
|
||||
if the field is not supported by the device, or other error messages on
|
||||
further failure.
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_parser_new 3
|
||||
.Xr dc_parser_set_data 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -39,6 +39,8 @@
|
||||
.Fa "dc_parser_t **parser"
|
||||
.Fa "dc_context_t *context"
|
||||
.Fa "dc_descriptor_t *descriptor"
|
||||
.Fa "unsigned int devtime"
|
||||
.Fa "dc_ticks_t systime"
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
Creates a parser for a single dive extracted from the dive computer with
|
||||
@ -53,6 +55,10 @@ parameter; and
|
||||
.Nm dc_parser_new2 ,
|
||||
which is given device values (model, etc.) directly.
|
||||
.Pp
|
||||
After filling in the
|
||||
.Fa parser
|
||||
parameter, one usually sets parser data with
|
||||
.Xr dc_parser_set_data 3 .
|
||||
The pointer must later be freed with
|
||||
.Xr dc_parser_destroy 3 .
|
||||
.Sh RETURN VALUES
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
.Ft "typedef void"
|
||||
.Fo "(*dc_sample_callback_t)"
|
||||
.Fa "dc_sample_type_t type"
|
||||
.Fa "const dc_sample_value_t *value"
|
||||
.Fa "dc_sample_value_t value"
|
||||
.Fa "void *userdata"
|
||||
.Fc
|
||||
.Ft dc_status_t
|
||||
@ -42,7 +42,7 @@
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
Extract the samples taken during a dive as previously initialised with
|
||||
.Xr dc_parser_new 3 .
|
||||
.Xr dc_parser_set_data 3 .
|
||||
Each sample is passed to
|
||||
.Fa callback
|
||||
with the
|
||||
@ -63,7 +63,7 @@ closed.
|
||||
The following sample types may be raised:
|
||||
.Bl -tag -width Ds
|
||||
.It Dv DC_SAMPLE_TIME
|
||||
The time of the sample taken in milliseconds after the dive began.
|
||||
The time of the sample taken in seconds after the dive began.
|
||||
Set in the
|
||||
.Fa time
|
||||
field.
|
||||
@ -184,7 +184,7 @@ Returns
|
||||
.Dv DC_STATUS_OK
|
||||
on success and another code on failure.
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_parser_new 3
|
||||
.Xr dc_parser_set_data 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
65
doc/man/dc_parser_set_data.3
Normal file
65
doc/man/dc_parser_set_data.3
Normal file
@ -0,0 +1,65 @@
|
||||
.\"
|
||||
.\" libdivecomputer
|
||||
.\"
|
||||
.\" Copyright (C) 2017 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
.\"
|
||||
.\" 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
|
||||
.\"
|
||||
.Dd January 5, 2017
|
||||
.Dt DC_PARSER_SET_DATA 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm dc_parser_set_data
|
||||
.Nd assigns parse data to a dive parser
|
||||
.Sh LIBRARY
|
||||
.Lb libdivecomputer
|
||||
.Sh SYNOPSIS
|
||||
.In libdivecomputer/parser.h
|
||||
.Ft dc_status_t
|
||||
.Fo dc_parser_set_data
|
||||
.Fa "dc_parser_t *parser"
|
||||
.Fa "const unsigned char *data"
|
||||
.Fa "unsigned int size"
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
Assigns the binary sequence
|
||||
.Fa data
|
||||
of length
|
||||
.Fa size
|
||||
bytes to
|
||||
.Fa parser ,
|
||||
which was created with
|
||||
.Xr dc_parser_new 3 .
|
||||
How the data is parsed depends upon the values provided to
|
||||
.Xr dc_parser_new 3 .
|
||||
The data usually comes from the callback assigned to
|
||||
.Xr dc_device_foreach 3 .
|
||||
.Sh RETURN VALUES
|
||||
Returns
|
||||
.Dv DC_STATUS_OK
|
||||
on success and another code on failure.
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_device_foreach 3 ,
|
||||
.Xr dc_parser_new 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
library was written by
|
||||
.An Jef Driesen ,
|
||||
.Mt jef@libdivecomputer.org .
|
||||
The manpages were written by
|
||||
.An Kristaps Dzonsons ,
|
||||
.Mt kristaps@bsd.lv .
|
||||
@ -82,7 +82,9 @@ Iterate over all dives with
|
||||
.Xr dc_device_foreach 3 .
|
||||
.It
|
||||
For each iterated dive, create a new parser with
|
||||
.Xr dc_parser_new 3 .
|
||||
.Xr dc_parser_new 3
|
||||
and set the parsed data with
|
||||
.Xr dc_parser_set_data 3 .
|
||||
.It
|
||||
Get attributes of the parsed dive with
|
||||
.Xr dc_parser_get_field 3 .
|
||||
|
||||
@ -72,7 +72,6 @@ static const backend_table_t g_backends[] = {
|
||||
{"vtpro", DC_FAMILY_OCEANIC_VTPRO, 0x4245},
|
||||
{"veo250", DC_FAMILY_OCEANIC_VEO250, 0x424C},
|
||||
{"atom2", DC_FAMILY_OCEANIC_ATOM2, 0x4342},
|
||||
{"i330r", DC_FAMILY_PELAGIC_I330R, 0x4744},
|
||||
{"nemo", DC_FAMILY_MARES_NEMO, 0},
|
||||
{"puck", DC_FAMILY_MARES_PUCK, 7},
|
||||
{"darwin", DC_FAMILY_MARES_DARWIN, 0},
|
||||
@ -92,17 +91,13 @@ static const backend_table_t g_backends[] = {
|
||||
{"idive", DC_FAMILY_DIVESYSTEM_IDIVE, 0x03},
|
||||
{"cochran", DC_FAMILY_COCHRAN_COMMANDER, 0},
|
||||
{"divecomputereu", DC_FAMILY_TECDIVING_DIVECOMPUTEREU, 0},
|
||||
{"extreme", DC_FAMILY_MCLEAN_EXTREME, 0},
|
||||
{"mclean", DC_FAMILY_MCLEAN_EXTREME, 0},
|
||||
{"lynx", DC_FAMILY_LIQUIVISION_LYNX, 0},
|
||||
{"sp2", DC_FAMILY_SPORASUB_SP2, 0},
|
||||
{"excursion", DC_FAMILY_DEEPSIX_EXCURSION, 0},
|
||||
{"screen", DC_FAMILY_SEAC_SCREEN, 0},
|
||||
{"cosmiq", DC_FAMILY_DEEPBLU_COSMIQ, 0},
|
||||
{"s1", DC_FAMILY_OCEANS_S1, 0},
|
||||
{"freedom", DC_FAMILY_DIVESOFT_FREEDOM, 19},
|
||||
|
||||
// Not merged upstream yet
|
||||
{"descentmk1", DC_FAMILY_GARMIN, 0},
|
||||
{"cosmiq", DC_FAMILY_DEEPBLU, 0},
|
||||
{"oceans", DC_FAMILY_OCEANS_S1, 0},
|
||||
};
|
||||
|
||||
static const transport_table_t g_transports[] = {
|
||||
|
||||
@ -24,12 +24,10 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
@ -50,7 +48,7 @@
|
||||
#define RESET 1
|
||||
#endif
|
||||
|
||||
#if defined(__GLIBC__) || defined(__MINGW32__) || defined(BSD) || defined(__ANDROID__)
|
||||
#if defined(__GLIBC__) || defined(__MINGW32__) || defined(BSD)
|
||||
#define NOPERMUTATION "+"
|
||||
#else
|
||||
#define NOPERMUTATION ""
|
||||
@ -242,8 +240,7 @@ main (int argc, char *argv[])
|
||||
}
|
||||
|
||||
// Translate the help option into a command.
|
||||
char helpcmd[] = "help";
|
||||
char *argv_help[] = {helpcmd, NULL, NULL};
|
||||
char *argv_help[] = {(char *) "help", NULL, NULL};
|
||||
if (help || argv[0] == NULL) {
|
||||
if (argv[0]) {
|
||||
argv_help[1] = argv[0];
|
||||
|
||||
@ -24,11 +24,9 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
@ -80,12 +78,20 @@ dive_cb (const unsigned char *data, unsigned int size, const unsigned char *fing
|
||||
|
||||
// Create the parser.
|
||||
message ("Creating the parser.\n");
|
||||
rc = dc_parser_new (&parser, divedata->device, data, size);
|
||||
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);
|
||||
|
||||
@ -24,11 +24,9 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
@ -24,10 +24,8 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
@ -94,7 +92,7 @@ fwupdate (dc_context_t *context, dc_descriptor_t *descriptor, dc_transport_t tra
|
||||
rc = hw_ostc_device_fwupdate (device, hexfile);
|
||||
break;
|
||||
case DC_FAMILY_HW_OSTC3:
|
||||
rc = hw_ostc3_device_fwupdate (device, hexfile, false);
|
||||
rc = hw_ostc3_device_fwupdate (device, hexfile);
|
||||
break;
|
||||
case DC_FAMILY_DIVESYSTEM_IDIVE:
|
||||
rc = divesystem_idive_device_fwupdate (device, hexfile);
|
||||
|
||||
@ -24,10 +24,8 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
@ -24,10 +24,8 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
@ -24,11 +24,9 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
@ -54,17 +52,17 @@ parse (dc_buffer_t *buffer, dc_context_t *context, dc_descriptor_t *descriptor,
|
||||
|
||||
// Create the parser.
|
||||
message ("Creating the parser.\n");
|
||||
rc = dc_parser_new2 (&parser, context, descriptor, data, size);
|
||||
rc = dc_parser_new2 (&parser, context, descriptor, devtime, systime);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR ("Error creating the parser.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Set the clock.
|
||||
message ("Setting the clock.\n");
|
||||
rc = dc_parser_set_clock (parser, devtime, systime);
|
||||
if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
|
||||
ERROR ("Error setting the clock.");
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -154,7 +152,7 @@ dctool_parse_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
for (unsigned int i = 0; i < argc; ++i) {
|
||||
// Read the input file.
|
||||
buffer = dctool_file_read (argv[i]);
|
||||
if (buffer == NULL) {
|
||||
|
||||
@ -24,10 +24,8 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
@ -24,10 +24,8 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
@ -160,7 +158,7 @@ dctool_scan_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t
|
||||
|
||||
// Show help message.
|
||||
if (help) {
|
||||
dctool_command_showhelp (&dctool_scan);
|
||||
dctool_command_showhelp (&dctool_list);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@ -24,10 +24,8 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
@ -24,10 +24,8 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
@ -24,10 +24,8 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
@ -80,7 +80,7 @@ mktemplate_datetime (char *buffer, size_t size, dc_parser_t *parser)
|
||||
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 || (size_t) n >= size)
|
||||
if (n < 0 || n >= size)
|
||||
return -1;
|
||||
|
||||
return n;
|
||||
@ -92,7 +92,7 @@ mktemplate_number (char *buffer, size_t size, unsigned int number)
|
||||
int n = 0;
|
||||
|
||||
n = snprintf (buffer, size, "%04u", number);
|
||||
if (n < 0 || (size_t) n >= size)
|
||||
if (n < 0 || n >= size)
|
||||
return -1;
|
||||
|
||||
return n;
|
||||
|
||||
@ -90,7 +90,7 @@ convert_volume (double value, dctool_units_t units)
|
||||
}
|
||||
|
||||
static void
|
||||
sample_cb (dc_sample_type_t type, const dc_sample_value_t *value, void *userdata)
|
||||
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",
|
||||
@ -104,80 +104,64 @@ sample_cb (dc_sample_type_t type, const dc_sample_value_t *value, void *userdata
|
||||
|
||||
sample_data_t *sampledata = (sample_data_t *) userdata;
|
||||
|
||||
unsigned int seconds = 0, milliseconds = 0;
|
||||
|
||||
switch (type) {
|
||||
case DC_SAMPLE_TIME:
|
||||
seconds = value->time / 1000;
|
||||
milliseconds = value->time % 1000;
|
||||
if (sampledata->nsamples++)
|
||||
fprintf (sampledata->ostream, "</sample>\n");
|
||||
fprintf (sampledata->ostream, "<sample>\n");
|
||||
if (milliseconds) {
|
||||
fprintf (sampledata->ostream, " <time>%02u:%02u.%03u</time>\n", seconds / 60, seconds % 60, milliseconds);
|
||||
} else {
|
||||
fprintf (sampledata->ostream, " <time>%02u:%02u</time>\n", seconds / 60, seconds % 60);
|
||||
}
|
||||
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",
|
||||
convert_depth(value->depth, sampledata->units));
|
||||
convert_depth(value.depth, sampledata->units));
|
||||
break;
|
||||
case DC_SAMPLE_PRESSURE:
|
||||
fprintf (sampledata->ostream, " <pressure tank=\"%u\">%.2f</pressure>\n",
|
||||
value->pressure.tank,
|
||||
convert_pressure(value->pressure.value, sampledata->units));
|
||||
value.pressure.tank,
|
||||
convert_pressure(value.pressure.value, sampledata->units));
|
||||
break;
|
||||
case DC_SAMPLE_TEMPERATURE:
|
||||
fprintf (sampledata->ostream, " <temperature>%.2f</temperature>\n",
|
||||
convert_temperature(value->temperature, sampledata->units));
|
||||
convert_temperature(value.temperature, sampledata->units));
|
||||
break;
|
||||
case DC_SAMPLE_EVENT:
|
||||
if (value->event.type != SAMPLE_EVENT_GASCHANGE && value->event.type != SAMPLE_EVENT_GASCHANGE2) {
|
||||
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]);
|
||||
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);
|
||||
fprintf (sampledata->ostream, " <rbt>%u</rbt>\n", value.rbt);
|
||||
break;
|
||||
case DC_SAMPLE_HEARTBEAT:
|
||||
fprintf (sampledata->ostream, " <heartbeat>%u</heartbeat>\n", value->heartbeat);
|
||||
fprintf (sampledata->ostream, " <heartbeat>%u</heartbeat>\n", value.heartbeat);
|
||||
break;
|
||||
case DC_SAMPLE_BEARING:
|
||||
fprintf (sampledata->ostream, " <bearing>%u</bearing>\n", value->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", ((const unsigned char *) value->vendor.data)[i]);
|
||||
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", ((const 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);
|
||||
fprintf (sampledata->ostream, " <setpoint>%.2f</setpoint>\n", value.setpoint);
|
||||
break;
|
||||
case DC_SAMPLE_PPO2:
|
||||
if (value->ppo2.sensor != DC_SENSOR_NONE) {
|
||||
fprintf (sampledata->ostream, " <ppo2 sensor=\"%u\">%.2f</ppo2>\n", value->ppo2.sensor, value->ppo2.value);
|
||||
} else {
|
||||
fprintf (sampledata->ostream, " <ppo2>%.2f</ppo2>\n", value->ppo2.value);
|
||||
}
|
||||
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);
|
||||
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,
|
||||
convert_depth(value->deco.depth, sampledata->units),
|
||||
decostop[value->deco.type]);
|
||||
if (value->deco.tts) {
|
||||
fprintf (sampledata->ostream, " <tts>%u</tts>\n",
|
||||
value->deco.tts);
|
||||
}
|
||||
value.deco.time,
|
||||
convert_depth(value.deco.depth, sampledata->units),
|
||||
decostop[value.deco.type]);
|
||||
break;
|
||||
case DC_SAMPLE_GASMIX:
|
||||
fprintf (sampledata->ostream, " <gasmix>%u</gasmix>\n", value->gasmix);
|
||||
fprintf (sampledata->ostream, " <gasmix>%u</gasmix>\n", value.gasmix);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -254,7 +238,7 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
||||
fprintf (output->ostream, "<datetime>%04i-%02i-%02i %02i:%02i:%02i %+03i:%02i</datetime>\n",
|
||||
dt.year, dt.month, dt.day,
|
||||
dt.hour, dt.minute, dt.second,
|
||||
dt.timezone / 3600, (abs(dt.timezone) % 3600) / 60);
|
||||
dt.timezone / 3600, (dt.timezone % 3600) / 60);
|
||||
}
|
||||
|
||||
// Parse the divetime.
|
||||
@ -338,19 +322,11 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
||||
"<gasmix>\n"
|
||||
" <he>%.1f</he>\n"
|
||||
" <o2>%.1f</o2>\n"
|
||||
" <n2>%.1f</n2>\n",
|
||||
" <n2>%.1f</n2>\n"
|
||||
"</gasmix>\n",
|
||||
gasmix.helium * 100.0,
|
||||
gasmix.oxygen * 100.0,
|
||||
gasmix.nitrogen * 100.0);
|
||||
if (gasmix.usage) {
|
||||
const char *usage[] = {"none", "oxygen", "diluent", "sidemount"};
|
||||
fprintf (output->ostream,
|
||||
" <usage>%s</usage>\n",
|
||||
usage[gasmix.usage]);
|
||||
}
|
||||
fprintf (output->ostream,
|
||||
"</gasmix>\n");
|
||||
|
||||
}
|
||||
|
||||
// Parse the tanks.
|
||||
@ -378,12 +354,6 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
||||
" <gasmix>%u</gasmix>\n",
|
||||
tank.gasmix);
|
||||
}
|
||||
if (tank.usage) {
|
||||
const char *usage[] = {"none", "oxygen", "diluent", "sidemount"};
|
||||
fprintf (output->ostream,
|
||||
" <usage>%s</usage>\n",
|
||||
usage[tank.usage]);
|
||||
}
|
||||
if (tank.type != DC_TANKVOLUME_NONE) {
|
||||
fprintf (output->ostream,
|
||||
" <type>%s</type>\n"
|
||||
@ -416,30 +386,6 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
||||
names[divemode]);
|
||||
}
|
||||
|
||||
// Parse the deco model.
|
||||
message ("Parsing the deco model.\n");
|
||||
dc_decomodel_t decomodel = {DC_DECOMODEL_NONE};
|
||||
status = dc_parser_get_field (parser, DC_FIELD_DECOMODEL, 0, &decomodel);
|
||||
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
|
||||
ERROR ("Error parsing the deco model.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (status != DC_STATUS_UNSUPPORTED) {
|
||||
const char *names[] = {"none", "buhlmann", "vpm", "rgbm", "dciem"};
|
||||
fprintf (output->ostream, "<decomodel>%s</decomodel>\n",
|
||||
names[decomodel.type]);
|
||||
if (decomodel.type == DC_DECOMODEL_BUHLMANN &&
|
||||
(decomodel.params.gf.low != 0 || decomodel.params.gf.high != 0)) {
|
||||
fprintf (output->ostream, "<gf>%u/%u</gf>\n",
|
||||
decomodel.params.gf.low, decomodel.params.gf.high);
|
||||
}
|
||||
if (decomodel.conservatism) {
|
||||
fprintf (output->ostream, "<conservatism>%d</conservatism>\n",
|
||||
decomodel.conservatism);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the salinity.
|
||||
message ("Parsing the salinity.\n");
|
||||
dc_salinity_t salinity = {DC_WATER_FRESH, 0.0};
|
||||
@ -450,14 +396,8 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
||||
}
|
||||
|
||||
if (status != DC_STATUS_UNSUPPORTED) {
|
||||
const char *names[] = {"fresh", "salt"};
|
||||
if (salinity.density) {
|
||||
fprintf (output->ostream, "<salinity density=\"%.1f\">%s</salinity>\n",
|
||||
salinity.density, names[salinity.type]);
|
||||
} else {
|
||||
fprintf (output->ostream, "<salinity>%s</salinity>\n",
|
||||
names[salinity.type]);
|
||||
}
|
||||
fprintf (output->ostream, "<salinity type=\"%u\">%.1f</salinity>\n",
|
||||
salinity.type, salinity.density);
|
||||
}
|
||||
|
||||
// Parse the atmospheric pressure.
|
||||
|
||||
@ -26,12 +26,6 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#endif
|
||||
|
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
||||
#define FUNCTION __func__
|
||||
#else
|
||||
|
||||
@ -36,6 +36,9 @@ atomics_cobalt_device_version (dc_device_t *device, unsigned char data[], unsign
|
||||
dc_status_t
|
||||
atomics_cobalt_device_set_simulation (dc_device_t *device, unsigned int simulation);
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -33,21 +33,6 @@ extern "C" {
|
||||
*/
|
||||
#define DC_IOCTL_BLE_GET_NAME DC_IOCTL_IOR('b', 0, DC_IOCTL_SIZE_VARIABLE)
|
||||
|
||||
/**
|
||||
* Get the bluetooth authentication PIN code.
|
||||
*
|
||||
* The data format is a NULL terminated string.
|
||||
*/
|
||||
#define DC_IOCTL_BLE_GET_PINCODE DC_IOCTL_IOR('b', 1, DC_IOCTL_SIZE_VARIABLE)
|
||||
|
||||
/**
|
||||
* Get/set the bluetooth authentication access code.
|
||||
*
|
||||
* The data format is a variable sized byte array.
|
||||
*/
|
||||
#define DC_IOCTL_BLE_GET_ACCESSCODE DC_IOCTL_IOR('b', 2, DC_IOCTL_SIZE_VARIABLE)
|
||||
#define DC_IOCTL_BLE_SET_ACCESSCODE DC_IOCTL_IOW('b', 2, DC_IOCTL_SIZE_VARIABLE)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -51,9 +51,6 @@ dc_buffer_append (dc_buffer_t *buffer, const unsigned char data[], size_t size);
|
||||
int
|
||||
dc_buffer_prepend (dc_buffer_t *buffer, const unsigned char data[], size_t size);
|
||||
|
||||
int
|
||||
dc_buffer_insert (dc_buffer_t *buffer, size_t offset, const unsigned char data[], size_t size);
|
||||
|
||||
int
|
||||
dc_buffer_slice (dc_buffer_t *buffer, size_t offset, size_t size);
|
||||
|
||||
|
||||
@ -78,7 +78,6 @@ typedef enum dc_family_t {
|
||||
DC_FAMILY_OCEANIC_VTPRO = (4 << 16),
|
||||
DC_FAMILY_OCEANIC_VEO250,
|
||||
DC_FAMILY_OCEANIC_ATOM2,
|
||||
DC_FAMILY_PELAGIC_I330R,
|
||||
/* Mares */
|
||||
DC_FAMILY_MARES_NEMO = (5 << 16),
|
||||
DC_FAMILY_MARES_PUCK,
|
||||
@ -113,22 +112,14 @@ typedef enum dc_family_t {
|
||||
DC_FAMILY_MCLEAN_EXTREME = (16 << 16),
|
||||
/* Liquivision */
|
||||
DC_FAMILY_LIQUIVISION_LYNX = (17 << 16),
|
||||
/* Sporasub */
|
||||
DC_FAMILY_SPORASUB_SP2 = (18 << 16),
|
||||
/* Deep Six */
|
||||
DC_FAMILY_DEEPSIX_EXCURSION = (19 << 16),
|
||||
/* Seac Screen */
|
||||
DC_FAMILY_SEAC_SCREEN = (20 << 16),
|
||||
/* Deepblu Cosmiq */
|
||||
DC_FAMILY_DEEPBLU_COSMIQ = (21 << 16),
|
||||
/* Oceans S1 */
|
||||
DC_FAMILY_OCEANS_S1 = (22 << 16),
|
||||
/* Divesoft Freedom */
|
||||
DC_FAMILY_DIVESOFT_FREEDOM = (23 << 16),
|
||||
|
||||
// Not merged upstream yet
|
||||
/* Garmin */
|
||||
DC_FAMILY_GARMIN = (100 << 16),
|
||||
/* Deepblu */
|
||||
DC_FAMILY_DEEPBLU = (101 << 16),
|
||||
/* Oceans S1 */
|
||||
DC_FAMILY_OCEANS_S1 = (102 << 16),
|
||||
} dc_family_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -22,13 +22,11 @@
|
||||
#ifndef DC_DATETIME_H
|
||||
#define DC_DATETIME_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define DC_TIMEZONE_NONE INT_MIN
|
||||
#define DC_TIMEZONE_NONE 0x80000000
|
||||
|
||||
#if defined (_WIN32) && !defined (__GNUC__)
|
||||
typedef __int64 dc_ticks_t;
|
||||
|
||||
@ -29,96 +29,29 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* Opaque object representing a supported dive computer.
|
||||
*/
|
||||
typedef struct dc_descriptor_t dc_descriptor_t;
|
||||
|
||||
/**
|
||||
* Create an iterator to enumerate the supported dive computers.
|
||||
*
|
||||
* @param[out] iterator A location to store the iterator.
|
||||
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
|
||||
* on failure.
|
||||
*/
|
||||
dc_status_t
|
||||
dc_descriptor_iterator (dc_iterator_t **iterator);
|
||||
|
||||
/**
|
||||
* Free the device descriptor.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
*/
|
||||
void
|
||||
dc_descriptor_free (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Get the vendor name of the dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @returns The vendor name of the dive computer on success, or NULL on failure.
|
||||
*/
|
||||
const char *
|
||||
dc_descriptor_get_vendor (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Get the product name of the dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @returns The product name of the dive computer on success, or NULL on
|
||||
* failure.
|
||||
*/
|
||||
const char *
|
||||
dc_descriptor_get_product (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Get the family type of the dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @returns The family type of the dive computer on success, or DC_FAMILY_NULL
|
||||
* on failure.
|
||||
*/
|
||||
dc_family_t
|
||||
dc_descriptor_get_type (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Get the model number of the dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @returns The model number of the dive computer on success, or zero on
|
||||
* failure.
|
||||
*/
|
||||
unsigned int
|
||||
dc_descriptor_get_model (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Get all transports supported by the dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @returns A bitmask with all the transports supported by the dive computer on
|
||||
* success, or DC_TRANSPORT_NONE on failure.
|
||||
*/
|
||||
unsigned int
|
||||
dc_descriptor_get_transports (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Check if a low-level I/O device matches a supported dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @param[in] transport The transport type of the I/O device.
|
||||
* @param[in] userdata A pointer to a transport specific data structure:
|
||||
* - DC_TRANSPORT_SERIAL: Name of the device node (string)
|
||||
* - DC_TRANSPORT_USB: USB VID/PID (#dc_usb_desc_t)
|
||||
* - DC_TRANSPORT_USBHID: USB VID/PID (#dc_usbhid_desc_t)
|
||||
* - DC_TRANSPORT_IRDA: IrDA device name (string)
|
||||
* - DC_TRANSPORT_BLUETOOTH: Bluetooth device name (string)
|
||||
* - DC_TRANSPORT_BLE: Bluetooth device name (string)
|
||||
* @returns Non-zero if the device matches a supported dive computer, or zero if
|
||||
* there is no match.
|
||||
*/
|
||||
int
|
||||
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -22,8 +22,6 @@
|
||||
#ifndef DC_HW_OSTC3_H
|
||||
#define DC_HW_OSTC3_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "device.h"
|
||||
#include "datetime.h"
|
||||
@ -57,7 +55,7 @@ dc_status_t
|
||||
hw_ostc3_device_config_reset (dc_device_t *abstract);
|
||||
|
||||
dc_status_t
|
||||
hw_ostc3_device_fwupdate (dc_device_t *abstract, const char *filename, bool forceUpdate);
|
||||
hw_ostc3_device_fwupdate (dc_device_t *abstract, const char *filename);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -67,7 +67,6 @@ typedef enum dc_field_type_t {
|
||||
DC_FIELD_TANK_COUNT,
|
||||
DC_FIELD_TANK,
|
||||
DC_FIELD_DIVEMODE,
|
||||
DC_FIELD_DECOMODEL,
|
||||
DC_FIELD_STRING,
|
||||
} dc_field_type_t;
|
||||
|
||||
@ -173,26 +172,19 @@ typedef struct dc_salinity_t {
|
||||
double density;
|
||||
} dc_salinity_t;
|
||||
|
||||
typedef enum dc_usage_t {
|
||||
DC_USAGE_NONE, // Usage not specified
|
||||
DC_USAGE_OXYGEN,
|
||||
DC_USAGE_DILUENT,
|
||||
DC_USAGE_OPEN_CIRCUIT,
|
||||
} dc_usage_t;
|
||||
|
||||
typedef struct dc_gasmix_t {
|
||||
double helium;
|
||||
double oxygen;
|
||||
double nitrogen;
|
||||
dc_usage_t usage;
|
||||
} dc_gasmix_t;
|
||||
|
||||
#define DC_SENSOR_NONE 0xFFFFFFFF
|
||||
#define DC_GASMIX_UNKNOWN 0xFFFFFFFF
|
||||
|
||||
typedef unsigned int dc_tankinfo_t;
|
||||
#define DC_TANKINFO_METRIC 1
|
||||
#define DC_TANKINFO_IMPERIAL 2
|
||||
#define DC_TANKINFO_CC_DILUENT 4
|
||||
#define DC_TANKINFO_CC_O2 8
|
||||
|
||||
// For backwards compatibility
|
||||
#define DC_TANKVOLUME_NONE 0
|
||||
@ -222,11 +214,6 @@ typedef unsigned int dc_tankinfo_t;
|
||||
* divide by 1 ATM (Vair = Vwater * Pwork / Patm).
|
||||
*/
|
||||
|
||||
typedef enum dc_tank_usage_t {
|
||||
DC_TANK_USAGE_NONE,
|
||||
DC_TANK_USAGE_SIDEMOUNT,
|
||||
} dc_tank_usage_t;
|
||||
|
||||
typedef struct dc_tank_t {
|
||||
unsigned int gasmix; /* Gas mix index, or DC_GASMIX_UNKNOWN */
|
||||
dc_tankinfo_t type; /* Tank type - metric/imperial and oc/cc */
|
||||
@ -234,53 +221,15 @@ typedef struct dc_tank_t {
|
||||
double workpressure; /* Work pressure (bar) */
|
||||
double beginpressure; /* Begin pressure (bar) */
|
||||
double endpressure; /* End pressure (bar) */
|
||||
dc_tank_usage_t usage;
|
||||
} dc_tank_t;
|
||||
|
||||
typedef enum dc_decomodel_type_t {
|
||||
DC_DECOMODEL_NONE,
|
||||
DC_DECOMODEL_BUHLMANN,
|
||||
DC_DECOMODEL_VPM,
|
||||
DC_DECOMODEL_RGBM,
|
||||
DC_DECOMODEL_DCIEM,
|
||||
} dc_decomodel_type_t;
|
||||
|
||||
/*
|
||||
* Decompression model
|
||||
*
|
||||
* The type field contains the decompression algorithm.
|
||||
*
|
||||
* The (optional) conservatism field contains the personal adjustment
|
||||
* setting of the algorithm. The exact interpretation depends on the
|
||||
* dive computer, but the default value (zero) will typically correspond
|
||||
* to the neutral setting, while a positive value is more conservative
|
||||
* and a negative value more aggressive.
|
||||
*
|
||||
* The (optional) params field contains the parameters of the algorithm:
|
||||
*
|
||||
* DC_DECOMODEL_BUHLMANN: The Gradient Factor (GF) parameters low and
|
||||
* high. For a pure Buhlmann algorithm (e.g. without GF enabled), both
|
||||
* values are 100. If GF are enabled, but the actual parameter values
|
||||
* are not available from the dive computer, both values are zero.
|
||||
*/
|
||||
typedef struct dc_decomodel_t {
|
||||
dc_decomodel_type_t type;
|
||||
int conservatism;
|
||||
union {
|
||||
struct {
|
||||
unsigned int high;
|
||||
unsigned int low;
|
||||
} gf;
|
||||
} params;
|
||||
} dc_decomodel_t;
|
||||
|
||||
typedef struct dc_field_string_t {
|
||||
const char *desc;
|
||||
const char *value;
|
||||
} dc_field_string_t;
|
||||
|
||||
typedef union dc_sample_value_t {
|
||||
unsigned int time; /* Milliseconds */
|
||||
unsigned int time;
|
||||
double depth;
|
||||
struct {
|
||||
unsigned int tank;
|
||||
@ -303,41 +252,31 @@ typedef union dc_sample_value_t {
|
||||
const void *data;
|
||||
} vendor;
|
||||
double setpoint;
|
||||
struct {
|
||||
unsigned int sensor;
|
||||
double value;
|
||||
} ppo2;
|
||||
double ppo2;
|
||||
double cns;
|
||||
struct {
|
||||
unsigned int type;
|
||||
unsigned int time;
|
||||
double depth;
|
||||
unsigned int tts;
|
||||
} deco;
|
||||
unsigned int gasmix; /* Gas mix index */
|
||||
} dc_sample_value_t;
|
||||
|
||||
typedef struct dc_parser_t dc_parser_t;
|
||||
|
||||
typedef void (*dc_sample_callback_t) (dc_sample_type_t type, const dc_sample_value_t *value, void *userdata);
|
||||
typedef void (*dc_sample_callback_t) (dc_sample_type_t type, dc_sample_value_t value, void *userdata);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_new (dc_parser_t **parser, dc_device_t *device, const unsigned char data[], size_t size);
|
||||
dc_parser_new (dc_parser_t **parser, dc_device_t *device);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_new2 (dc_parser_t **parser, dc_context_t *context, dc_descriptor_t *descriptor, const unsigned char data[], size_t size);
|
||||
dc_parser_new2 (dc_parser_t **parser, dc_context_t *context, dc_descriptor_t *descriptor, unsigned int devtime, dc_ticks_t systime);
|
||||
|
||||
dc_family_t
|
||||
dc_parser_get_type (dc_parser_t *parser);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_set_clock (dc_parser_t *parser, unsigned int devtime, dc_ticks_t systime);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_set_atmospheric (dc_parser_t *parser, double atmospheric);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_set_density (dc_parser_t *parser, double density);
|
||||
dc_parser_set_data (dc_parser_t *parser, const unsigned char *data, unsigned int size);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime);
|
||||
|
||||
@ -35,6 +35,9 @@ extern "C" {
|
||||
dc_status_t
|
||||
reefnet_sensus_device_get_handshake (dc_device_t *device, unsigned char data[], unsigned int size);
|
||||
|
||||
dc_status_t
|
||||
reefnet_sensus_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -38,6 +38,9 @@ reefnet_sensuspro_device_get_handshake (dc_device_t *device, unsigned char data[
|
||||
dc_status_t
|
||||
reefnet_sensuspro_device_write_interval (dc_device_t *device, unsigned char interval);
|
||||
|
||||
dc_status_t
|
||||
reefnet_sensuspro_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -56,6 +56,9 @@ reefnet_sensusultra_device_write_parameter (dc_device_t *device, reefnet_sensusu
|
||||
dc_status_t
|
||||
reefnet_sensusultra_device_sense (dc_device_t *device, unsigned char data[], unsigned int size);
|
||||
|
||||
dc_status_t
|
||||
reefnet_sensusultra_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -86,14 +86,6 @@ typedef enum dc_usb_recipient_t {
|
||||
DC_USB_RECIPIENT_OTHER = 0x03,
|
||||
} dc_usb_recipient_t;
|
||||
|
||||
/**
|
||||
* USB device descriptor.
|
||||
*/
|
||||
typedef struct dc_usb_desc_t {
|
||||
unsigned short vid;
|
||||
unsigned short pid;
|
||||
} dc_usb_desc_t;
|
||||
|
||||
/**
|
||||
* Opaque object representing a USB device.
|
||||
*/
|
||||
|
||||
@ -32,14 +32,6 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* USB HID device descriptor.
|
||||
*/
|
||||
typedef struct dc_usbhid_desc_t {
|
||||
unsigned short vid;
|
||||
unsigned short pid;
|
||||
} dc_usbhid_desc_t;
|
||||
|
||||
/**
|
||||
* Opaque object representing a USB HID device.
|
||||
*/
|
||||
|
||||
995
msvc/libdivecomputer.vcproj
Normal file
995
msvc/libdivecomputer.vcproj
Normal file
@ -0,0 +1,995 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="libdivecomputer"
|
||||
ProjectGUID="{CEA7215A-D6B5-4840-8086-3C854F371997}"
|
||||
RootNamespace="libdivecomputer"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_AF_IRDA_H;HAVE_WS2BTH_H"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
CompileAs="2"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="ws2_32.lib"
|
||||
LinkIncremental="2"
|
||||
ModuleDefinitionFile="$(OutDir)/libdivecomputer.def"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
AdditionalIncludeDirectories="..\include"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_AF_IRDA_H;HAVE_WS2BTH_H"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
CompileAs="2"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="ws2_32.lib"
|
||||
LinkIncremental="1"
|
||||
ModuleDefinitionFile="$(OutDir)/libdivecomputer.def"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\src\aes.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\array.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\atomics_cobalt.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\atomics_cobalt_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\bluetooth.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\buffer.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\checksum.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\citizen_aqualand.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\citizen_aqualand_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cochran_commander.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cochran_commander_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\common.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\context.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_edy.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_edy_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_goa.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_goa_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_leonardo.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_leonardo_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\custom.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\datetime.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\descriptor.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\device.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\diverite_nitekq.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\diverite_nitekq_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\divesystem_idive.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\divesystem_idive_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hw_frog.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hw_ostc.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hw_ostc3.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hw_ostc_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ihex.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\iostream.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\irda.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\iterator.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\liquivision_lynx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\liquivision_lynx_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_common.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_darwin.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_darwin_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_iconhd.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_iconhd_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_nemo.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_nemo_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_puck.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mclean_extreme.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mclean_extreme_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_atom2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_atom2_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_common.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_veo250.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_veo250_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_vtpro.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_vtpro_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\rbstream.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensus.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensus_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensuspro.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensuspro_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensusultra.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensusultra_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ringbuffer.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\serial_win32.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\shearwater_common.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\shearwater_petrel.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\shearwater_predator.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\shearwater_predator_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\socket.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_common.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_common2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_d9.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_d9_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_eon.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_eon_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_eonsteel.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_eonsteel_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_solution.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_solution_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_vyper.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_vyper2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_vyper_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\tecdiving_divecomputereu.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\tecdiving_divecomputereu_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\garmin.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\garmin_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\deepblu.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\deepblu_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mclean_extreme.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mclean_extreme_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceans_s1.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceans_s1_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\field-cache.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\timer.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\usb.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\usbhid.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_aladin.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_memomouse.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_memomouse_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_smart.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_smart_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\version.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\zeagle_n2ition3.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\src\aes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\array.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\atomics_cobalt.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\atomics_cobalt.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\bluetooth.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\buffer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\checksum.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\citizen_aqualand.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cochran_commander.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\common-private.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\context-private.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\context.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_edy.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_goa.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_leonardo.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\custom.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\datetime.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\descriptor.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\device-private.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\device.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\diverite_nitekq.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\divesystem_idive.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\hw_frog.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hw_frog.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\hw_ostc.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hw_ostc.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hw_ostc3.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\hw_ostc3.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ihex.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\iostream-private.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\iostream.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\irda.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\iterator-private.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\iterator.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\liquivision_lynx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_common.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_darwin.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_iconhd.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_nemo.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_puck.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mclean_extreme.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_atom2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\oceanic_atom2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_common.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_veo250.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\oceanic_veo250.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_vtpro.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\oceanic_vtpro.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\parser-private.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\parser.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\platform.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\rbstream.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensus.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\reefnet_sensus.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensuspro.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\reefnet_sensuspro.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\reefnet_sensusultra.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensusultra.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\revision.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ringbuffer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\serial.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\shearwater_common.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\shearwater_petrel.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\shearwater_predator.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\socket.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_common.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_common2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\suunto_d9.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_d9.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\suunto_eon.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_eon.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_eonsteel.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_solution.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_vyper.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\suunto_vyper2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_vyper2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\tecdiving_divecomputereu.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\garmin.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\deepblu.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mclean_extreme.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceans_s1.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\timer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\units.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\usb.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\usbhid.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_aladin.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_memomouse.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_smart.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\version.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\zeagle_n2ition3.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\src\libdivecomputer.rc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\libdivecomputer.symbols"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="echo EXPORTS > "$(OutDir)/libdivecomputer.def" && type "$(InputPath)" >> "$(OutDir)/libdivecomputer.def""
|
||||
Outputs="$(OutDir)/libdivecomputer.def"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="echo EXPORTS > "$(OutDir)/libdivecomputer.def" && type "$(InputPath)" >> "$(OutDir)/libdivecomputer.def""
|
||||
Outputs="$(OutDir)/libdivecomputer.def"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@ -16,7 +16,7 @@ endif
|
||||
|
||||
libdivecomputer_la_SOURCES = \
|
||||
version.c \
|
||||
descriptor.c \
|
||||
descriptor-private.h descriptor.c \
|
||||
iostream-private.h iostream.c \
|
||||
iterator-private.h iterator.c \
|
||||
common-private.h common.c \
|
||||
@ -43,7 +43,6 @@ libdivecomputer_la_SOURCES = \
|
||||
oceanic_atom2.h oceanic_atom2.c oceanic_atom2_parser.c \
|
||||
oceanic_veo250.h oceanic_veo250.c oceanic_veo250_parser.c \
|
||||
oceanic_vtpro.h oceanic_vtpro.c oceanic_vtpro_parser.c \
|
||||
pelagic_i330r.h pelagic_i330r.c \
|
||||
mares_common.h mares_common.c \
|
||||
mares_nemo.h mares_nemo.c mares_nemo_parser.c \
|
||||
mares_puck.h mares_puck.c \
|
||||
@ -65,7 +64,7 @@ libdivecomputer_la_SOURCES = \
|
||||
diverite_nitekq.h diverite_nitekq.c diverite_nitekq_parser.c \
|
||||
citizen_aqualand.h citizen_aqualand.c citizen_aqualand_parser.c \
|
||||
divesystem_idive.h divesystem_idive.c divesystem_idive_parser.c \
|
||||
platform.h platform.c \
|
||||
platform.h \
|
||||
ringbuffer.h ringbuffer.c \
|
||||
rbstream.h rbstream.c \
|
||||
checksum.h checksum.c \
|
||||
@ -75,15 +74,6 @@ libdivecomputer_la_SOURCES = \
|
||||
tecdiving_divecomputereu.h tecdiving_divecomputereu.c tecdiving_divecomputereu_parser.c \
|
||||
mclean_extreme.h mclean_extreme.c mclean_extreme_parser.c \
|
||||
liquivision_lynx.h liquivision_lynx.c liquivision_lynx_parser.c \
|
||||
sporasub_sp2.h sporasub_sp2.c sporasub_sp2_parser.c \
|
||||
deepsix_excursion.h deepsix_excursion.c deepsix_excursion_parser.c \
|
||||
seac_screen.h seac_screen.c seac_screen_parser.c \
|
||||
deepblu_cosmiq.h deepblu_cosmiq.c deepblu_cosmiq_parser.c \
|
||||
oceans_s1_common.h oceans_s1_common.c \
|
||||
oceans_s1.h oceans_s1.c oceans_s1_parser.c \
|
||||
divesoft_freedom.h divesoft_freedom.c divesoft_freedom_parser.c \
|
||||
hdlc.h hdlc.c \
|
||||
packet.h packet.c \
|
||||
socket.h socket.c \
|
||||
irda.c \
|
||||
usb.c \
|
||||
@ -95,7 +85,9 @@ libdivecomputer_la_SOURCES = \
|
||||
libdivecomputer_la_SOURCES += \
|
||||
usb_storage.c \
|
||||
field-cache.h field-cache.c \
|
||||
garmin.h garmin.c garmin_parser.c
|
||||
garmin.h garmin.c garmin_parser.c \
|
||||
deepblu.h deepblu.c deepblu_parser.c \
|
||||
oceans_s1.h oceans_s1.c oceans_s1_parser.c
|
||||
|
||||
if OS_WIN32
|
||||
libdivecomputer_la_SOURCES += serial_win32.c
|
||||
@ -113,7 +105,7 @@ libdivecomputer.exp: libdivecomputer.symbols
|
||||
$(AM_V_GEN) sed -e '/^$$/d' $< > $@
|
||||
|
||||
.rc.lo:
|
||||
$(AM_V_GEN) $(LIBTOOL) --silent --tag=CC --mode=compile $(RC) $(DEFS) $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $< -o $@
|
||||
$(AM_V_GEN) $(LIBTOOL) --silent --tag=CC --mode=compile $(RC) $(DEFS) $(DEFAULT_INCLUDES) $< -o $@
|
||||
|
||||
libdivecomputer.lo: revision.h
|
||||
|
||||
|
||||
@ -98,7 +98,7 @@ typedef struct aes_state_t {
|
||||
|
||||
#if defined(CBC) && CBC
|
||||
// Initial Vector used only for CBC mode
|
||||
const uint8_t* Iv;
|
||||
uint8_t* Iv;
|
||||
#endif
|
||||
} aes_state_t;
|
||||
|
||||
@ -542,7 +542,7 @@ void AES128_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length,
|
||||
|
||||
if(iv != 0)
|
||||
{
|
||||
state.Iv = iv;
|
||||
state.Iv = (uint8_t*)iv;
|
||||
}
|
||||
|
||||
for(i = 0; i < length; i += KEYLEN)
|
||||
@ -584,7 +584,7 @@ void AES128_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length,
|
||||
// If iv is passed as 0, we continue to encrypt without re-setting the Iv
|
||||
if(iv != 0)
|
||||
{
|
||||
state.Iv = iv;
|
||||
state.Iv = (uint8_t*)iv;
|
||||
}
|
||||
|
||||
for(i = 0; i < length; i += KEYLEN)
|
||||
|
||||
187
src/array.c
187
src/array.c
@ -160,30 +160,6 @@ array_convert_str2num (const unsigned char data[], unsigned int size)
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
array_convert_bin2dec (const unsigned char data[], unsigned int size)
|
||||
{
|
||||
unsigned int value = 0;
|
||||
for (unsigned int i = 0; i < size; ++i) {
|
||||
value *= 100;
|
||||
value += data[i];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
array_convert_bcd2dec (const unsigned char data[], unsigned int size)
|
||||
{
|
||||
unsigned int value = 0;
|
||||
for (unsigned int i = 0; i < size; ++i) {
|
||||
value *= 100;
|
||||
value += bcd2dec(data[i]);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
array_uint_be (const unsigned char data[], unsigned int n)
|
||||
{
|
||||
@ -208,32 +184,6 @@ array_uint_le (const unsigned char data[], unsigned int n)
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned long long
|
||||
array_uint64_be (const unsigned char data[])
|
||||
{
|
||||
return ((unsigned long long) data[0] << 56) |
|
||||
((unsigned long long) data[1] << 48) |
|
||||
((unsigned long long) data[2] << 40) |
|
||||
((unsigned long long) data[3] << 32) |
|
||||
((unsigned long long) data[4] << 24) |
|
||||
((unsigned long long) data[5] << 16) |
|
||||
((unsigned long long) data[6] << 8) |
|
||||
((unsigned long long) data[7] << 0);
|
||||
}
|
||||
|
||||
unsigned long long
|
||||
array_uint64_le (const unsigned char data[])
|
||||
{
|
||||
return ((unsigned long long) data[0] << 0) |
|
||||
((unsigned long long) data[1] << 8) |
|
||||
((unsigned long long) data[2] << 16) |
|
||||
((unsigned long long) data[3] << 24) |
|
||||
((unsigned long long) data[4] << 32) |
|
||||
((unsigned long long) data[5] << 40) |
|
||||
((unsigned long long) data[6] << 48) |
|
||||
((unsigned long long) data[7] << 56);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
array_uint32_be (const unsigned char data[])
|
||||
{
|
||||
@ -263,6 +213,17 @@ array_uint32_word_be (const unsigned char data[])
|
||||
((unsigned int) data[3] << 16);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
array_uint32_le_set (unsigned char data[], const unsigned int input)
|
||||
{
|
||||
data[0] = input & 0xFF;
|
||||
data[1] = (input >> 8) & 0xFF;
|
||||
data[2] = (input >> 16) & 0xFF;
|
||||
data[3] = (input >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
array_uint24_be (const unsigned char data[])
|
||||
{
|
||||
@ -271,6 +232,16 @@ array_uint24_be (const unsigned char data[])
|
||||
((unsigned int) data[2] << 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
array_uint24_be_set (unsigned char data[], const unsigned int input)
|
||||
{
|
||||
data[0] = (input >> 16) & 0xFF;
|
||||
data[1] = (input >> 8) & 0xFF;
|
||||
data[2] = input & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
array_uint24_le (const unsigned char data[])
|
||||
{
|
||||
@ -294,124 +265,8 @@ array_uint16_le (const unsigned char data[])
|
||||
((unsigned int) data[1] << 8);
|
||||
}
|
||||
|
||||
void
|
||||
array_uint64_be_set (unsigned char data[], const unsigned long long input)
|
||||
{
|
||||
data[0] = (input >> 56) & 0xFF;
|
||||
data[1] = (input >> 48) & 0xFF;
|
||||
data[2] = (input >> 40) & 0xFF;
|
||||
data[3] = (input >> 32) & 0xFF;
|
||||
data[4] = (input >> 24) & 0xFF;
|
||||
data[5] = (input >> 16) & 0xFF;
|
||||
data[6] = (input >> 8) & 0xFF;
|
||||
data[7] = (input ) & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
array_uint64_le_set (unsigned char data[], const unsigned long long input)
|
||||
{
|
||||
data[0] = (input ) & 0xFF;
|
||||
data[1] = (input >> 8) & 0xFF;
|
||||
data[2] = (input >> 16) & 0xFF;
|
||||
data[3] = (input >> 24) & 0xFF;
|
||||
data[4] = (input >> 32) & 0xFF;
|
||||
data[5] = (input >> 40) & 0xFF;
|
||||
data[6] = (input >> 48) & 0xFF;
|
||||
data[7] = (input >> 56) & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
array_uint32_be_set (unsigned char data[], const unsigned int input)
|
||||
{
|
||||
data[0] = (input >> 24) & 0xFF;
|
||||
data[1] = (input >> 16) & 0xFF;
|
||||
data[2] = (input >> 8) & 0xFF;
|
||||
data[3] = (input ) & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
array_uint32_le_set (unsigned char data[], const unsigned int input)
|
||||
{
|
||||
data[0] = (input ) & 0xFF;
|
||||
data[1] = (input >> 8) & 0xFF;
|
||||
data[2] = (input >> 16) & 0xFF;
|
||||
data[3] = (input >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
array_uint24_be_set (unsigned char data[], const unsigned int input)
|
||||
{
|
||||
data[0] = (input >> 16) & 0xFF;
|
||||
data[1] = (input >> 8) & 0xFF;
|
||||
data[2] = (input ) & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
array_uint24_le_set (unsigned char data[], const unsigned int input)
|
||||
{
|
||||
data[0] = (input ) & 0xFF;
|
||||
data[1] = (input >> 8) & 0xFF;
|
||||
data[2] = (input >> 16) & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
array_uint16_be_set (unsigned char data[], const unsigned short input)
|
||||
{
|
||||
data[0] = (input >> 8) & 0xFF;
|
||||
data[1] = (input ) & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
array_uint16_le_set (unsigned char data[], const unsigned short input)
|
||||
{
|
||||
data[0] = (input ) & 0xFF;
|
||||
data[1] = (input >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
unsigned char
|
||||
bcd2dec (unsigned char value)
|
||||
{
|
||||
return ((value >> 4) & 0x0f) * 10 + (value & 0x0f);
|
||||
}
|
||||
|
||||
unsigned char
|
||||
dec2bcd (unsigned char value)
|
||||
{
|
||||
if (value >= 100)
|
||||
return 0;
|
||||
|
||||
unsigned char hi = value / 10;
|
||||
unsigned char lo = value % 10;
|
||||
return (hi << 4) | lo;
|
||||
}
|
||||
|
||||
/*
|
||||
* When turning a two's-complement number with a certain number
|
||||
* of bits into one with more bits, the sign bit must be repeated
|
||||
* in all the extra bits.
|
||||
*/
|
||||
unsigned int
|
||||
signextend (unsigned int value, unsigned int nbits)
|
||||
{
|
||||
if (nbits <= 0 || nbits > 32)
|
||||
return 0;
|
||||
|
||||
unsigned int signbit = 1U << (nbits - 1);
|
||||
unsigned int mask = signbit - 1;
|
||||
|
||||
if ((value & signbit) == signbit)
|
||||
return value | ~mask;
|
||||
else
|
||||
return value & mask;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
popcount (unsigned int value)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
while (value) {
|
||||
value &= value - 1;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
53
src/array.h
53
src/array.h
@ -22,8 +22,6 @@
|
||||
#ifndef ARRAY_H
|
||||
#define ARRAY_H
|
||||
|
||||
#define C_ARRAY_SIZE(a) (sizeof (a) / sizeof *(a))
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
@ -54,24 +52,12 @@ array_convert_hex2bin (const unsigned char input[], unsigned int isize, unsigned
|
||||
unsigned int
|
||||
array_convert_str2num (const unsigned char data[], unsigned int size);
|
||||
|
||||
unsigned int
|
||||
array_convert_bin2dec (const unsigned char data[], unsigned int size);
|
||||
|
||||
unsigned int
|
||||
array_convert_bcd2dec (const unsigned char data[], unsigned int size);
|
||||
|
||||
unsigned int
|
||||
array_uint_be (const unsigned char data[], unsigned int n);
|
||||
|
||||
unsigned int
|
||||
array_uint_le (const unsigned char data[], unsigned int n);
|
||||
|
||||
unsigned long long
|
||||
array_uint64_be (const unsigned char data[]);
|
||||
|
||||
unsigned long long
|
||||
array_uint64_le (const unsigned char data[]);
|
||||
|
||||
unsigned int
|
||||
array_uint32_be (const unsigned char data[]);
|
||||
|
||||
@ -81,9 +67,15 @@ array_uint32_le (const unsigned char data[]);
|
||||
unsigned int
|
||||
array_uint32_word_be (const unsigned char data[]);
|
||||
|
||||
void
|
||||
array_uint32_le_set (unsigned char data[], const unsigned int input);
|
||||
|
||||
unsigned int
|
||||
array_uint24_be (const unsigned char data[]);
|
||||
|
||||
void
|
||||
array_uint24_be_set (unsigned char data[], const unsigned int input);
|
||||
|
||||
unsigned int
|
||||
array_uint24_le (const unsigned char data[]);
|
||||
|
||||
@ -93,42 +85,9 @@ array_uint16_be (const unsigned char data[]);
|
||||
unsigned short
|
||||
array_uint16_le (const unsigned char data[]);
|
||||
|
||||
void
|
||||
array_uint64_be_set (unsigned char data[], const unsigned long long input);
|
||||
|
||||
void
|
||||
array_uint64_le_set (unsigned char data[], const unsigned long long input);
|
||||
|
||||
void
|
||||
array_uint32_be_set (unsigned char data[], const unsigned int input);
|
||||
|
||||
void
|
||||
array_uint32_le_set (unsigned char data[], const unsigned int input);
|
||||
|
||||
void
|
||||
array_uint24_be_set (unsigned char data[], const unsigned int input);
|
||||
|
||||
void
|
||||
array_uint24_le_set (unsigned char data[], const unsigned int input);
|
||||
|
||||
void
|
||||
array_uint16_be_set (unsigned char data[], const unsigned short input);
|
||||
|
||||
void
|
||||
array_uint16_le_set (unsigned char data[], const unsigned short input);
|
||||
|
||||
unsigned char
|
||||
bcd2dec (unsigned char value);
|
||||
|
||||
unsigned char
|
||||
dec2bcd (unsigned char value);
|
||||
|
||||
unsigned int
|
||||
signextend (unsigned int value, unsigned int nbits);
|
||||
|
||||
unsigned int
|
||||
popcount (unsigned int value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -41,8 +41,6 @@
|
||||
|
||||
#define FP_OFFSET 20
|
||||
|
||||
#define SZ_HEADER 228
|
||||
|
||||
#define SZ_MEMORY1 (29 * 64 * 1024) // Cobalt 1
|
||||
#define SZ_MEMORY2 (41 * 64 * 1024) // Cobalt 2
|
||||
#define SZ_VERSION 14
|
||||
@ -212,15 +210,6 @@ atomics_cobalt_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init,
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Adjust the maximum value to take into account the two byte checksum and
|
||||
// the 8 byte serial number. Those extra bytes are not stored inside the
|
||||
// dive header and are added dynamically during the data transfer. Since we
|
||||
// don't know the total number of dives in advance, we can't calculate the
|
||||
// total number of extra bytes and adjust the maximum on the fly.
|
||||
if (progress) {
|
||||
progress->maximum += 2 + 8;
|
||||
}
|
||||
|
||||
// Send the command to the dive computer.
|
||||
unsigned char bRequest = 0;
|
||||
if (device->simulation)
|
||||
@ -349,12 +338,6 @@ atomics_cobalt_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (size < SZ_HEADER) {
|
||||
ERROR (abstract->context, "Dive header is too small (%u).", size);
|
||||
dc_buffer_free (buffer);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
if (memcmp (data + FP_OFFSET, device->fingerprint, sizeof (device->fingerprint)) == 0) {
|
||||
dc_buffer_free (buffer);
|
||||
return DC_STATUS_SUCCESS;
|
||||
@ -365,6 +348,12 @@ atomics_cobalt_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Adjust the maximum value to take into account the two checksum bytes
|
||||
// for the next dive. Since we don't know the total number of dives in
|
||||
// advance, we can't calculate the total number of checksum bytes and
|
||||
// adjust the maximum on the fly.
|
||||
progress.maximum += 2;
|
||||
|
||||
ndives++;
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
atomics_cobalt_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
atomics_cobalt_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -46,10 +46,11 @@ typedef struct atomics_cobalt_parser_t atomics_cobalt_parser_t;
|
||||
struct atomics_cobalt_parser_t {
|
||||
dc_parser_t base;
|
||||
// Depth calibration.
|
||||
double atmospheric;
|
||||
double hydrostatic;
|
||||
};
|
||||
|
||||
static dc_status_t atomics_cobalt_parser_set_density (dc_parser_t *abstract, double density);
|
||||
static dc_status_t atomics_cobalt_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
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);
|
||||
@ -57,9 +58,7 @@ static dc_status_t atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract,
|
||||
static const dc_parser_vtable_t atomics_cobalt_parser_vtable = {
|
||||
sizeof(atomics_cobalt_parser_t),
|
||||
DC_FAMILY_ATOMICS_COBALT,
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
atomics_cobalt_parser_set_density, /* set_density */
|
||||
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 */
|
||||
@ -68,7 +67,7 @@ static const dc_parser_vtable_t atomics_cobalt_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
{
|
||||
atomics_cobalt_parser_t *parser = NULL;
|
||||
|
||||
@ -76,14 +75,15 @@ atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context, const un
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (atomics_cobalt_parser_t *) dc_parser_allocate (context, &atomics_cobalt_parser_vtable, data, size);
|
||||
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;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
parser->hydrostatic = DEF_DENSITY_SALT * GRAVITY;
|
||||
parser->atmospheric = 0.0;
|
||||
parser->hydrostatic = 1025.0 * GRAVITY;
|
||||
|
||||
*out = (dc_parser_t*) parser;
|
||||
|
||||
@ -92,11 +92,22 @@ atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context, const un
|
||||
|
||||
|
||||
static dc_status_t
|
||||
atomics_cobalt_parser_set_density (dc_parser_t *abstract, double density)
|
||||
atomics_cobalt_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
atomics_cobalt_parser_t *parser = (atomics_cobalt_parser_t *) abstract;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
parser->hydrostatic = density * GRAVITY;
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_parser_set_calibration (dc_parser_t *abstract, double atmospheric, double hydrostatic)
|
||||
{
|
||||
atomics_cobalt_parser_t *parser = (atomics_cobalt_parser_t*) abstract;
|
||||
|
||||
if (!ISINSTANCE (abstract))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
parser->atmospheric = atmospheric;
|
||||
parser->hydrostatic = hydrostatic;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
@ -140,10 +151,15 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
dc_tank_t *tank = (dc_tank_t *) value;
|
||||
|
||||
unsigned int atmospheric = array_uint16_le (p + 0x26);
|
||||
double atmospheric = 0.0;
|
||||
char buf[BUFLEN];
|
||||
dc_field_string_t *string = (dc_field_string_t *) value;
|
||||
|
||||
if (parser->atmospheric)
|
||||
atmospheric = parser->atmospheric;
|
||||
else
|
||||
atmospheric = array_uint16_le (p + 0x26) * BAR / 1000.0;
|
||||
|
||||
unsigned int workpressure = 0;
|
||||
|
||||
if (value) {
|
||||
@ -152,14 +168,13 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
*((unsigned int *) value) = array_uint16_le (p + 0x58) * 60;
|
||||
break;
|
||||
case DC_FIELD_MAXDEPTH:
|
||||
*((double *) value) = (signed int)(array_uint16_le (p + 0x56) - atmospheric) * (BAR / 1000.0) / parser->hydrostatic;
|
||||
*((double *) value) = (array_uint16_le (p + 0x56) * BAR / 1000.0 - atmospheric) / parser->hydrostatic;
|
||||
break;
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
case DC_FIELD_TANK_COUNT:
|
||||
*((unsigned int *) value) = p[0x2a];
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = p[SZ_HEADER + SZ_GASMIX * flags + 5] / 100.0;
|
||||
gasmix->oxygen = p[SZ_HEADER + SZ_GASMIX * flags + 4] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -191,7 +206,6 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
tank->gasmix = flags;
|
||||
tank->beginpressure = array_uint16_le(p + 6) * PSI / BAR;
|
||||
tank->endpressure = array_uint16_le(p + 14) * PSI / BAR;
|
||||
tank->usage = DC_TANK_USAGE_NONE;
|
||||
break;
|
||||
case DC_FIELD_DIVEMODE:
|
||||
switch(p[0x24]) {
|
||||
@ -206,9 +220,6 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
*((double *) value) = atmospheric / 1000.0;
|
||||
break;
|
||||
case DC_FIELD_STRING:
|
||||
switch(flags) {
|
||||
case 0: // Serialnr
|
||||
@ -263,7 +274,11 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
if (size < header + SZ_SEGMENT * nsegments)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int atmospheric = array_uint16_le (data + 0x26);
|
||||
double atmospheric = 0.0;
|
||||
if (parser->atmospheric)
|
||||
atmospheric = parser->atmospheric;
|
||||
else
|
||||
atmospheric = array_uint16_le (data + 0x26) * BAR / 1000.0;
|
||||
|
||||
// Previous gas mix - initialize with impossible value
|
||||
unsigned int gasmix_previous = 0xFFFFFFFF;
|
||||
@ -289,19 +304,19 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
|
||||
// Time (seconds).
|
||||
time += interval;
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
|
||||
// Depth (1/1000 bar).
|
||||
unsigned int depth = array_uint16_le (data + offset + 0);
|
||||
sample.depth = (signed int)(depth - atmospheric) * (BAR / 1000.0) / parser->hydrostatic;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
sample.depth = (depth * BAR / 1000.0 - atmospheric) / parser->hydrostatic;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
|
||||
// Pressure (1 psi).
|
||||
unsigned int pressure = array_uint16_le (data + offset + 2);
|
||||
sample.pressure.tank = tank;
|
||||
sample.pressure.value = pressure * PSI / BAR;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
|
||||
// Current gas mix
|
||||
unsigned int gasmix = data[offset + 4];
|
||||
@ -317,14 +332,14 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
// Temperature (1 °F).
|
||||
unsigned int temperature = data[offset + 8];
|
||||
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
|
||||
// violation status
|
||||
sample.event.type = 0;
|
||||
@ -334,15 +349,15 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
unsigned int violation = data[offset + 11];
|
||||
if (violation & 0x01) {
|
||||
sample.event.type = SAMPLE_EVENT_ASCENT;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
}
|
||||
if (violation & 0x04) {
|
||||
sample.event.type = SAMPLE_EVENT_CEILING;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
}
|
||||
if (violation & 0x08) {
|
||||
sample.event.type = SAMPLE_EVENT_PO2;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
}
|
||||
|
||||
// NDL & deco
|
||||
@ -357,8 +372,7 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.time = ndl;
|
||||
sample.deco.depth = 0.0;
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
|
||||
offset += SZ_SEGMENT;
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h> // malloc, free
|
||||
#include <stdio.h>
|
||||
|
||||
#include "socket.h"
|
||||
|
||||
@ -51,6 +52,7 @@
|
||||
#include "context-private.h"
|
||||
#include "iostream-private.h"
|
||||
#include "iterator-private.h"
|
||||
#include "descriptor-private.h"
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -229,7 +231,7 @@ dc_bluetooth_addr2str(dc_bluetooth_address_t address, char *str, size_t size)
|
||||
if (str == NULL || size < DC_BLUETOOTH_SIZE)
|
||||
return NULL;
|
||||
|
||||
int n = dc_platform_snprintf(str, size, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
int n = snprintf(str, size, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
(unsigned char)((address >> 40) & 0xFF),
|
||||
(unsigned char)((address >> 32) & 0xFF),
|
||||
(unsigned char)((address >> 24) & 0xFF),
|
||||
@ -454,7 +456,7 @@ dc_bluetooth_iterator_next (dc_iterator_t *abstract, void *out)
|
||||
INFO (abstract->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s",
|
||||
address, name ? name : "");
|
||||
|
||||
if (!dc_descriptor_filter (iterator->descriptor, DC_TRANSPORT_BLUETOOTH, name)) {
|
||||
if (!dc_descriptor_filter (iterator->descriptor, DC_TRANSPORT_BLUETOOTH, name, NULL)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
66
src/buffer.c
66
src/buffer.c
@ -231,72 +231,6 @@ dc_buffer_prepend (dc_buffer_t *buffer, const unsigned char data[], size_t size)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
dc_buffer_insert (dc_buffer_t *buffer, size_t offset, const unsigned char data[], size_t size)
|
||||
{
|
||||
if (buffer == NULL)
|
||||
return 0;
|
||||
|
||||
if (offset > buffer->size)
|
||||
return 0;
|
||||
|
||||
size_t head = buffer->offset;
|
||||
size_t tail = buffer->capacity - (buffer->offset + buffer->size);
|
||||
|
||||
unsigned char *ptr = buffer->data + buffer->offset;
|
||||
|
||||
if (size <= head) {
|
||||
if (buffer->size)
|
||||
memmove (ptr - size, ptr, offset);
|
||||
buffer->offset -= size;
|
||||
} else if (size <= tail) {
|
||||
if (buffer->size)
|
||||
memmove (ptr + offset + size, ptr + offset, buffer->size - offset);
|
||||
} else if (size <= tail + head) {
|
||||
size_t n = buffer->size + size;
|
||||
size_t available = buffer->capacity - n;
|
||||
|
||||
size_t tmp_offset = head > tail ? available : 0;
|
||||
|
||||
unsigned char *tmp = buffer->data;
|
||||
|
||||
if (buffer->size) {
|
||||
memmove (tmp + tmp_offset, ptr, offset);
|
||||
memmove (tmp + tmp_offset + offset + size, ptr + offset, buffer->size - offset);
|
||||
}
|
||||
|
||||
buffer->offset = tmp_offset;
|
||||
} else {
|
||||
size_t n = buffer->size + size;
|
||||
size_t capacity = dc_buffer_expand_calc (buffer, n);
|
||||
size_t available = capacity - n;
|
||||
|
||||
size_t tmp_offset = head > tail ? available : 0;
|
||||
|
||||
unsigned char *tmp = (unsigned char *) malloc (capacity);
|
||||
if (tmp == NULL)
|
||||
return 0;
|
||||
|
||||
if (buffer->size) {
|
||||
memcpy (tmp + tmp_offset, ptr, offset);
|
||||
memcpy (tmp + tmp_offset + offset + size, ptr + offset, buffer->size - offset);
|
||||
}
|
||||
|
||||
free (buffer->data);
|
||||
buffer->data = tmp;
|
||||
buffer->capacity = capacity;
|
||||
buffer->offset = tmp_offset;
|
||||
}
|
||||
|
||||
if (size)
|
||||
memcpy (buffer->data + buffer->offset + offset, data, size);
|
||||
|
||||
buffer->size += size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
dc_buffer_slice (dc_buffer_t *buffer, size_t offset, size_t size)
|
||||
{
|
||||
|
||||
180
src/checksum.c
180
src/checksum.c
@ -68,13 +68,8 @@ checksum_xor_uint8 (const unsigned char data[], unsigned int size, unsigned char
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Polynomial: 0x1021
|
||||
* RefIn: False
|
||||
* RefOut: False
|
||||
*/
|
||||
unsigned short
|
||||
checksum_crc16_ccitt (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout)
|
||||
checksum_crc16_ccitt (const unsigned char data[], unsigned int size, unsigned short init)
|
||||
{
|
||||
static const unsigned short crc_ccitt_table[] = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
|
||||
@ -115,170 +110,11 @@ checksum_crc16_ccitt (const unsigned char data[], unsigned int size, unsigned sh
|
||||
for (unsigned int i = 0; i < size; ++i)
|
||||
crc = (crc << 8) ^ crc_ccitt_table[(crc >> 8) ^ data[i]];
|
||||
|
||||
return crc ^ xorout;
|
||||
return crc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Polynomial: 0x1021
|
||||
* RefIn: True
|
||||
* RefOut: True
|
||||
*/
|
||||
unsigned short
|
||||
checksum_crc16r_ccitt (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout)
|
||||
{
|
||||
static const unsigned short crc_ccitt_table[] = {
|
||||
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
|
||||
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
|
||||
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
|
||||
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
|
||||
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
|
||||
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
|
||||
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
|
||||
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
|
||||
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
|
||||
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
|
||||
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
|
||||
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
|
||||
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
|
||||
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
|
||||
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
|
||||
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
|
||||
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
|
||||
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
|
||||
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
|
||||
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
|
||||
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
|
||||
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
|
||||
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
|
||||
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
|
||||
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
|
||||
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
|
||||
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
|
||||
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
|
||||
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
|
||||
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
|
||||
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
|
||||
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
|
||||
};
|
||||
|
||||
unsigned short crc = init;
|
||||
for (unsigned int i = 0; i < size; ++i)
|
||||
crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ data[i]) & 0xff];
|
||||
|
||||
return crc ^ xorout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Polynomial: 0x8005
|
||||
* RefIn: False
|
||||
* RefOut: False
|
||||
*/
|
||||
unsigned short
|
||||
checksum_crc16_ansi (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout)
|
||||
{
|
||||
static const unsigned short crc_ccitt_table[] = {
|
||||
0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
|
||||
0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
|
||||
0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
|
||||
0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
|
||||
0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
|
||||
0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
|
||||
0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
|
||||
0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
|
||||
0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
|
||||
0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
|
||||
0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
|
||||
0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
|
||||
0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
|
||||
0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
|
||||
0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
|
||||
0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
|
||||
0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
|
||||
0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
|
||||
0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
|
||||
0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
|
||||
0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
|
||||
0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
|
||||
0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
|
||||
0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
|
||||
0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
|
||||
0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
|
||||
0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
|
||||
0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
|
||||
0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
|
||||
0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
|
||||
0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
|
||||
0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
|
||||
};
|
||||
|
||||
unsigned short crc = init;
|
||||
for (unsigned int i = 0; i < size; ++i)
|
||||
crc = (crc << 8) ^ crc_ccitt_table[(crc >> 8) ^ data[i]];
|
||||
|
||||
return crc ^ xorout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Polynomial: 0x8005
|
||||
* RefIn: True
|
||||
* RefOut: True
|
||||
*/
|
||||
unsigned short
|
||||
checksum_crc16r_ansi (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout)
|
||||
{
|
||||
static const unsigned short crc_ccitt_table[] = {
|
||||
0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
|
||||
0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
|
||||
0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
|
||||
0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
|
||||
0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
|
||||
0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
|
||||
0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
|
||||
0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
|
||||
0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
|
||||
0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
|
||||
0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
|
||||
0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
|
||||
0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
|
||||
0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
|
||||
0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
|
||||
0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
|
||||
0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
|
||||
0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
|
||||
0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
|
||||
0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
|
||||
0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
|
||||
0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
|
||||
0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
|
||||
0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
|
||||
0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
|
||||
0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
|
||||
0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
|
||||
0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
|
||||
0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
|
||||
0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
|
||||
0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
|
||||
0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
|
||||
};
|
||||
|
||||
unsigned short crc = init;
|
||||
for (unsigned int i = 0; i < size; ++i)
|
||||
crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ data[i]) & 0xff];
|
||||
|
||||
return crc ^ xorout;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Polynomial: 0x04C11DB7
|
||||
* Init: 0xffffffff
|
||||
* XorOut: 0xffffffff
|
||||
* RefIn: True
|
||||
* RefOut: True
|
||||
*/
|
||||
unsigned int
|
||||
checksum_crc32r (const unsigned char data[], unsigned int size)
|
||||
checksum_crc32 (const unsigned char data[], unsigned int size)
|
||||
{
|
||||
static const unsigned int crc_table[] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
@ -322,16 +158,8 @@ checksum_crc32r (const unsigned char data[], unsigned int size)
|
||||
return crc ^ 0xffffffff;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Polynomial: 0x04C11DB7
|
||||
* Init: 0xffffffff
|
||||
* XorOut: 0xffffffff
|
||||
* RefIn: False
|
||||
* RefOut: False
|
||||
*/
|
||||
unsigned int
|
||||
checksum_crc32 (const unsigned char data[], unsigned int size)
|
||||
checksum_crc32b (const unsigned char data[], unsigned int size)
|
||||
{
|
||||
static const unsigned int crc_table[] = {
|
||||
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
|
||||
|
||||
@ -39,23 +39,14 @@ unsigned char
|
||||
checksum_xor_uint8 (const unsigned char data[], unsigned int size, unsigned char init);
|
||||
|
||||
unsigned short
|
||||
checksum_crc16_ccitt (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout);
|
||||
|
||||
unsigned short
|
||||
checksum_crc16r_ccitt (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout);
|
||||
|
||||
unsigned short
|
||||
checksum_crc16_ansi (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout);
|
||||
|
||||
unsigned short
|
||||
checksum_crc16r_ansi (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout);
|
||||
|
||||
unsigned int
|
||||
checksum_crc32r (const unsigned char data[], unsigned int size);
|
||||
checksum_crc16_ccitt (const unsigned char data[], unsigned int size, unsigned short init);
|
||||
|
||||
unsigned int
|
||||
checksum_crc32 (const unsigned char data[], unsigned int size);
|
||||
|
||||
unsigned int
|
||||
checksum_crc32b (const unsigned char data[], unsigned int size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -31,8 +31,6 @@
|
||||
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &citizen_aqualand_device_vtable)
|
||||
|
||||
#define SZ_HEADER 32
|
||||
|
||||
typedef struct citizen_aqualand_device_t {
|
||||
dc_device_t base;
|
||||
dc_iostream_t *iostream;
|
||||
@ -202,12 +200,6 @@ citizen_aqualand_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
unsigned char *data = dc_buffer_get_data (buffer);
|
||||
unsigned int size = dc_buffer_get_size (buffer);
|
||||
|
||||
if (size < SZ_HEADER) {
|
||||
ERROR (abstract->context, "Dive header is too small (%u).", size);
|
||||
dc_buffer_free (buffer);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
if (callback && memcmp (data + 0x05, device->fingerprint, sizeof (device->fingerprint)) != 0) {
|
||||
callback (data, size, data + 0x05, sizeof (device->fingerprint), userdata);
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
citizen_aqualand_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
citizen_aqualand_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
citizen_aqualand_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ typedef struct citizen_aqualand_parser_t {
|
||||
dc_parser_t base;
|
||||
} citizen_aqualand_parser_t;
|
||||
|
||||
static dc_status_t citizen_aqualand_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
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);
|
||||
@ -43,9 +44,7 @@ static dc_status_t citizen_aqualand_parser_samples_foreach (dc_parser_t *abstrac
|
||||
static const dc_parser_vtable_t citizen_aqualand_parser_vtable = {
|
||||
sizeof(citizen_aqualand_parser_t),
|
||||
DC_FAMILY_CITIZEN_AQUALAND,
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
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 */
|
||||
@ -54,7 +53,7 @@ static const dc_parser_vtable_t citizen_aqualand_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
{
|
||||
citizen_aqualand_parser_t *parser = NULL;
|
||||
|
||||
@ -62,7 +61,7 @@ citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context, const
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (citizen_aqualand_parser_t *) dc_parser_allocate (context, &citizen_aqualand_parser_vtable, data, size);
|
||||
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;
|
||||
@ -74,6 +73,13 @@ citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context, const
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
citizen_aqualand_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -232,15 +238,15 @@ citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
|
||||
// Time
|
||||
time += interval;
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
|
||||
// Depth
|
||||
if (metric)
|
||||
sample.depth = depth / 10.0;
|
||||
else
|
||||
sample.depth = depth * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
|
||||
// Temperature
|
||||
if (time % 300 == 0) {
|
||||
@ -251,7 +257,7 @@ citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
sample.temperature = temperature / 10.0;
|
||||
else
|
||||
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,6 +30,8 @@
|
||||
#include "ringbuffer.h"
|
||||
#include "rbstream.h"
|
||||
|
||||
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
|
||||
|
||||
#define MAXRETRIES 2
|
||||
|
||||
#define COCHRAN_MODEL_COMMANDER_TM 0
|
||||
@ -39,8 +41,6 @@
|
||||
#define COCHRAN_MODEL_EMC_16 4
|
||||
#define COCHRAN_MODEL_EMC_20 5
|
||||
|
||||
#define UNDEFINED 0xFFFFFFFF
|
||||
|
||||
typedef enum cochran_endian_t {
|
||||
ENDIAN_LE,
|
||||
ENDIAN_BE,
|
||||
@ -57,8 +57,8 @@ typedef struct cochran_data_t {
|
||||
unsigned char *logbook;
|
||||
|
||||
unsigned short int dive_count;
|
||||
unsigned int fp_dive_num;
|
||||
unsigned int invalid_profile_dive_num;
|
||||
int fp_dive_num;
|
||||
int invalid_profile_dive_num;
|
||||
|
||||
unsigned int logbook_size;
|
||||
} cochran_data_t;
|
||||
@ -621,17 +621,18 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d
|
||||
// We track profile ringbuffer usage to determine which dives have profile data
|
||||
int profile_capacity_remaining = device->layout->rb_profile_end - device->layout->rb_profile_begin;
|
||||
|
||||
unsigned int dive_count = 0;
|
||||
data->fp_dive_num = UNDEFINED;
|
||||
int dive_count = -1;
|
||||
data->fp_dive_num = -1;
|
||||
|
||||
// Start at end of log
|
||||
if (data->dive_count < device->layout->rb_logbook_entry_count)
|
||||
dive_count = data->dive_count;
|
||||
else
|
||||
dive_count = device->layout->rb_logbook_entry_count;
|
||||
dive_count--;
|
||||
|
||||
unsigned int sample_read_size = 0;
|
||||
data->invalid_profile_dive_num = UNDEFINED;
|
||||
data->invalid_profile_dive_num = -1;
|
||||
|
||||
// Remove the pre-dive events that occur after the last dive
|
||||
unsigned int rb_head_ptr = 0;
|
||||
@ -675,7 +676,7 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d
|
||||
|
||||
// Loop through dives to find FP, Accumulate profile data size,
|
||||
// and find the last dive with invalid profile
|
||||
for (unsigned int i = 0; i < dive_count; ++i) {
|
||||
for (unsigned int i = 0; i <= dive_count; ++i) {
|
||||
unsigned int idx = (device->layout->rb_logbook_entry_count + head_dive - (i + 1)) % device->layout->rb_logbook_entry_count;
|
||||
|
||||
unsigned char *log_entry = data->logbook + idx * device->layout->rb_logbook_entry_size;
|
||||
@ -952,7 +953,7 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
|
||||
}
|
||||
|
||||
// Change tail to dive following the fingerprint dive.
|
||||
if (data.fp_dive_num != UNDEFINED)
|
||||
if (data.fp_dive_num > -1)
|
||||
tail_dive = (data.fp_dive_num + 1) % layout->rb_logbook_entry_count;
|
||||
|
||||
// Number of dives to read
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
cochran_commander_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
cochran_commander_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
cochran_commander_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -29,6 +29,8 @@
|
||||
#include "parser-private.h"
|
||||
#include "array.h"
|
||||
|
||||
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
|
||||
|
||||
#define COCHRAN_MODEL_COMMANDER_TM 0
|
||||
#define COCHRAN_MODEL_COMMANDER_PRE21000 1
|
||||
#define COCHRAN_MODEL_COMMANDER_AIR_NITROX 2
|
||||
@ -99,6 +101,7 @@ typedef struct cochran_commander_parser_t {
|
||||
unsigned int nevents;
|
||||
} cochran_commander_parser_t ;
|
||||
|
||||
static dc_status_t cochran_commander_parser_set_data (dc_parser_t *parser, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t cochran_commander_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime);
|
||||
static dc_status_t cochran_commander_parser_get_field (dc_parser_t *parser, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t cochran_commander_parser_samples_foreach (dc_parser_t *parser, dc_sample_callback_t callback, void *userdata);
|
||||
@ -106,9 +109,7 @@ static dc_status_t cochran_commander_parser_samples_foreach (dc_parser_t *parser
|
||||
static const dc_parser_vtable_t cochran_commander_parser_vtable = {
|
||||
sizeof(cochran_commander_parser_t),
|
||||
DC_FAMILY_COCHRAN_COMMANDER,
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
cochran_commander_parser_set_data, /* set_data */
|
||||
cochran_commander_parser_get_datetime, /* datetime */
|
||||
cochran_commander_parser_get_field, /* fields */
|
||||
cochran_commander_parser_samples_foreach, /* samples_foreach */
|
||||
@ -313,7 +314,7 @@ cochran_commander_handle_event (cochran_commander_parser_t *parser, unsigned cha
|
||||
sample.event.time = 0;
|
||||
sample.event.value = 0;
|
||||
sample.event.flags = event->flag;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
}
|
||||
}
|
||||
|
||||
@ -350,7 +351,7 @@ cochran_commander_backparse(cochran_commander_parser_t *parser, const unsigned c
|
||||
|
||||
|
||||
dc_status_t
|
||||
cochran_commander_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
cochran_commander_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
{
|
||||
cochran_commander_parser_t *parser = NULL;
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
@ -359,7 +360,7 @@ cochran_commander_parser_create (dc_parser_t **out, dc_context_t *context, const
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (cochran_commander_parser_t *) dc_parser_allocate (context, &cochran_commander_parser_vtable, data, size);
|
||||
parser = (cochran_commander_parser_t *) dc_parser_allocate (context, &cochran_commander_parser_vtable);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -405,6 +406,13 @@ error_free:
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cochran_commander_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cochran_commander_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -505,7 +513,6 @@ cochran_commander_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
// Gas percentages are decimal and encoded as
|
||||
// highbyte = integer portion
|
||||
// lowbyte = decimal portion, divide by 256 to get decimal value
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->oxygen = array_uint16_le (data + layout->oxygen + 2 * flags) / 256.0 / 100;
|
||||
if (layout->helium == UNSUPPORTED) {
|
||||
gasmix->helium = 0;
|
||||
@ -570,26 +577,26 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
||||
unsigned int temp = samples[0]; // Half degrees F
|
||||
unsigned int depth = samples[1]; // Half feet
|
||||
|
||||
last_sample_time = sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
last_sample_time = sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
|
||||
sample.depth = (depth / 2.0) * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
|
||||
sample.temperature = (temp / 2.0 - 32.0) / 1.8;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
|
||||
sample.gasmix = 0;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
|
||||
while (offset < size) {
|
||||
const unsigned char *s = samples + offset;
|
||||
|
||||
sample.time = time * 1000;
|
||||
sample.time = time;
|
||||
if (last_sample_time != sample.time) {
|
||||
// We haven't issued this time yet.
|
||||
last_sample_time = sample.time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
}
|
||||
|
||||
if (*s & 0x80) {
|
||||
@ -607,8 +614,7 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.time = 60; // We don't know the duration
|
||||
sample.deco.depth = deco_ceiling * FEET;
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
||||
break;
|
||||
case 0xAD: // Increment ceiling (shallower)
|
||||
deco_ceiling -= 10; // feet
|
||||
@ -616,8 +622,7 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = deco_ceiling * FEET;
|
||||
sample.deco.time = 60; // We don't know the duration
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
||||
break;
|
||||
default:
|
||||
cochran_commander_handle_event(parser, s[0], callback, userdata);
|
||||
@ -630,7 +635,7 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
||||
else
|
||||
temp += (*s & 0x0f);
|
||||
sample.temperature = (temp / 2.0 - 32.0) / 1.8;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
}
|
||||
|
||||
offset++;
|
||||
@ -644,7 +649,7 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
||||
depth += s[0] & 0x3f;
|
||||
|
||||
sample.depth = (depth / 2.0) * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
|
||||
offset++;
|
||||
time += sample_interval;
|
||||
@ -708,27 +713,27 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
start_depth = array_uint16_le (data + layout->start_depth) / 256.0;
|
||||
}
|
||||
|
||||
last_sample_time = sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
last_sample_time = sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
|
||||
sample.depth = start_depth * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
|
||||
sample.temperature = (data[layout->start_temp] - 32.0) / 1.8;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
|
||||
sample.gasmix = 0;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
unsigned int last_gasmix = sample.gasmix;
|
||||
|
||||
while (offset < size) {
|
||||
const unsigned char *s = samples + offset;
|
||||
|
||||
sample.time = time * 1000;
|
||||
sample.time = time;
|
||||
if (last_sample_time != sample.time) {
|
||||
// We haven't issued this time yet.
|
||||
last_sample_time = sample.time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
}
|
||||
|
||||
// If corrupt_dive end before offset
|
||||
@ -768,8 +773,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.time = (array_uint16_le(s + 3) + 1) * 60;
|
||||
sample.deco.depth = deco_ceiling * FEET;
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
||||
break;
|
||||
case 0xAD: // Increment ceiling (shallower)
|
||||
deco_ceiling -= 10; // feet
|
||||
@ -777,8 +781,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = deco_ceiling * FEET;
|
||||
sample.deco.time = (array_uint16_le(s + 3) + 1) * 60;
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
||||
break;
|
||||
case 0xC0: // Switched to FO2 21% mode (surface)
|
||||
// Event seen upon surfacing
|
||||
@ -787,14 +790,14 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
case 0xEF: // Switched to gas blend 2
|
||||
if (last_gasmix != 1) {
|
||||
sample.gasmix = 1;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
last_gasmix = sample.gasmix;
|
||||
}
|
||||
break;
|
||||
case 0xF3: // Switched to gas blend 1
|
||||
if (last_gasmix != 0) {
|
||||
sample.gasmix = 0;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
last_gasmix = sample.gasmix;
|
||||
}
|
||||
break;
|
||||
@ -814,7 +817,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
depth += (s[0] & 0x3f);
|
||||
|
||||
sample.depth = (start_depth + depth / 4.0) * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
|
||||
// Ascent rate is logged in the 0th sample, temp in the 1st, repeat.
|
||||
if (time % 2 == 0) {
|
||||
@ -830,7 +833,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
double temperature = s[1] / 2.0 + 20.0;
|
||||
sample.temperature = (temperature - 32.0) / 1.8;
|
||||
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
}
|
||||
|
||||
// Cochran EMC models store NDL and deco stop time
|
||||
@ -851,8 +854,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.time = deco_time * 60;
|
||||
sample.deco.depth = 0;
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
}
|
||||
break;
|
||||
case 23:
|
||||
@ -862,8 +864,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = deco_ceiling * FEET;
|
||||
sample.deco.time = deco_time * 60;
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -28,8 +28,6 @@
|
||||
|
||||
#include <libdivecomputer/context.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
@ -42,6 +40,12 @@ extern "C" {
|
||||
#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
|
||||
|
||||
#ifdef ENABLE_LOGGING
|
||||
#define HEXDUMP(context, loglevel, prefix, data, size) dc_context_hexdump (context, loglevel, __FILE__, __LINE__, FUNCTION, prefix, data, size)
|
||||
#define SYSERROR(context, errcode) dc_context_syserror (context, DC_LOGLEVEL_ERROR, __FILE__, __LINE__, FUNCTION, errcode)
|
||||
@ -59,7 +63,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
dc_status_t
|
||||
dc_context_log (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *format, ...) DC_ATTR_FORMAT_PRINTF(6, 7);
|
||||
dc_context_log (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *format, ...) ATTR_FORMAT_PRINTF(6, 7);
|
||||
|
||||
dc_status_t
|
||||
dc_context_syserror (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, int errcode);
|
||||
|
||||
@ -25,8 +25,8 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
@ -35,7 +35,6 @@
|
||||
#endif
|
||||
|
||||
#include "context-private.h"
|
||||
#include "platform.h"
|
||||
#include "timer.h"
|
||||
|
||||
struct dc_context_t {
|
||||
@ -49,6 +48,55 @@ struct dc_context_t {
|
||||
};
|
||||
|
||||
#ifdef ENABLE_LOGGING
|
||||
/*
|
||||
* A wrapper for the vsnprintf function, which will always null terminate the
|
||||
* string and returns a negative value if the destination buffer is too small.
|
||||
*/
|
||||
static int
|
||||
l_vsnprintf (char *str, size_t size, const char *format, va_list ap)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (size == 0)
|
||||
return -1;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/*
|
||||
* The non-standard vsnprintf implementation provided by MSVC doesn't null
|
||||
* terminate the string and returns a negative value if the destination
|
||||
* buffer is too small.
|
||||
*/
|
||||
n = _vsnprintf (str, size - 1, format, ap);
|
||||
if (n == size - 1 || n < 0)
|
||||
str[size - 1] = 0;
|
||||
#else
|
||||
/*
|
||||
* The C99 vsnprintf function will always null terminate the string. If the
|
||||
* destination buffer is too small, the return value is the number of
|
||||
* characters that would have been written if the buffer had been large
|
||||
* enough.
|
||||
*/
|
||||
n = vsnprintf (str, size, format, ap);
|
||||
if (n >= size)
|
||||
n = -1;
|
||||
#endif
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
l_snprintf (char *str, size_t size, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int n;
|
||||
|
||||
va_start (ap, format);
|
||||
n = l_vsnprintf (str, size, format, ap);
|
||||
va_end (ap);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
l_hexdump (char *str, size_t size, const unsigned char data[], size_t n)
|
||||
{
|
||||
@ -56,7 +104,7 @@ l_hexdump (char *str, size_t size, const unsigned char data[], size_t n)
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
|
||||
if (size == 0 || size > INT_MAX)
|
||||
if (size == 0)
|
||||
return -1;
|
||||
|
||||
/* The maximum number of bytes. */
|
||||
@ -78,11 +126,11 @@ l_hexdump (char *str, size_t size, const unsigned char data[], size_t n)
|
||||
/* Null terminate the hex string. */
|
||||
str[length * 2] = 0;
|
||||
|
||||
return (n > maxlength ? -1 : (int) (length * 2));
|
||||
return (n > maxlength ? -1 : length * 2);
|
||||
}
|
||||
|
||||
static void
|
||||
loghandler (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *msg, void *userdata)
|
||||
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"};
|
||||
|
||||
@ -118,7 +166,7 @@ dc_context_new (dc_context_t **out)
|
||||
|
||||
#ifdef ENABLE_LOGGING
|
||||
context->loglevel = DC_LOGLEVEL_WARNING;
|
||||
context->logfunc = loghandler;
|
||||
context->logfunc = logfunc;
|
||||
#else
|
||||
context->loglevel = DC_LOGLEVEL_NONE;
|
||||
context->logfunc = NULL;
|
||||
@ -195,7 +243,7 @@ dc_context_log (dc_context_t *context, dc_loglevel_t loglevel, const char *file,
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
va_start (ap, format);
|
||||
dc_platform_vsnprintf (context->msg, sizeof (context->msg), format, ap);
|
||||
l_vsnprintf (context->msg, sizeof (context->msg), format, ap);
|
||||
va_end (ap);
|
||||
|
||||
context->logfunc (context, loglevel, file, line, function, context->msg, context->userdata);
|
||||
@ -261,7 +309,7 @@ dc_context_hexdump (dc_context_t *context, dc_loglevel_t loglevel, const char *f
|
||||
if (context->logfunc == NULL)
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
n = dc_platform_snprintf (context->msg, sizeof (context->msg), "%s: size=%u, data=", prefix, size);
|
||||
n = l_snprintf (context->msg, sizeof (context->msg), "%s: size=%u, data=", prefix, size);
|
||||
|
||||
if (n >= 0) {
|
||||
n = l_hexdump (context->msg + n, sizeof (context->msg) - n, data, size);
|
||||
|
||||
@ -38,8 +38,6 @@
|
||||
#define SZ_PACKET 0x80
|
||||
#define SZ_PAGE (SZ_PACKET / 4)
|
||||
|
||||
#define SZ_HEADER 32
|
||||
|
||||
#define IQ700 0x05
|
||||
#define EDY 0x08
|
||||
|
||||
@ -381,14 +379,7 @@ cressi_edy_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = device->model;
|
||||
devinfo.firmware = 0;
|
||||
devinfo.serial = 0;
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
return device_dump_read (abstract, 0, dc_buffer_get_data (buffer),
|
||||
return device_dump_read (abstract, dc_buffer_get_data (buffer),
|
||||
dc_buffer_get_size (buffer), SZ_PACKET);
|
||||
}
|
||||
|
||||
@ -524,13 +515,6 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (length < SZ_HEADER) {
|
||||
ERROR (abstract->context, "Dive header is too small (%u).", length);
|
||||
dc_rbstream_free (rbstream);
|
||||
free (buffer);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned char *p = buffer + offset;
|
||||
|
||||
if (memcmp (p, device->fingerprint, sizeof (device->fingerprint)) == 0)
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
cressi_edy_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
cressi_edy_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
cressi_edy_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -31,8 +31,6 @@
|
||||
#define IQ700 0x05
|
||||
#define EDY 0x08
|
||||
|
||||
#define SZ_HEADER 32
|
||||
|
||||
typedef struct cressi_edy_parser_t cressi_edy_parser_t;
|
||||
|
||||
struct cressi_edy_parser_t {
|
||||
@ -40,6 +38,7 @@ struct cressi_edy_parser_t {
|
||||
unsigned int model;
|
||||
};
|
||||
|
||||
static dc_status_t cressi_edy_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
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);
|
||||
@ -47,9 +46,7 @@ static dc_status_t cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_
|
||||
static const dc_parser_vtable_t cressi_edy_parser_vtable = {
|
||||
sizeof(cressi_edy_parser_t),
|
||||
DC_FAMILY_CRESSI_EDY,
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
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 */
|
||||
@ -73,7 +70,7 @@ cressi_edy_parser_count_gasmixes (const unsigned char *data)
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
{
|
||||
cressi_edy_parser_t *parser = NULL;
|
||||
|
||||
@ -81,7 +78,7 @@ cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, const unsign
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (cressi_edy_parser_t *) dc_parser_allocate (context, &cressi_edy_parser_vtable, data, size);
|
||||
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;
|
||||
@ -96,10 +93,17 @@ cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, const unsign
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cressi_edy_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
if (abstract->size < SZ_HEADER)
|
||||
if (abstract->size < 32)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
const unsigned char *p = abstract->data;
|
||||
@ -123,7 +127,7 @@ cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
||||
{
|
||||
cressi_edy_parser_t *parser = (cressi_edy_parser_t *) abstract;
|
||||
|
||||
if (abstract->size < SZ_HEADER)
|
||||
if (abstract->size < 32)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
const unsigned char *p = abstract->data;
|
||||
@ -145,7 +149,6 @@ cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
||||
*((unsigned int *) value) = cressi_edy_parser_count_gasmixes(p);
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->oxygen = bcd2dec (p[0x17 - flags]) / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -182,7 +185,7 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
unsigned int ngasmixes = cressi_edy_parser_count_gasmixes(data);
|
||||
unsigned int gasmix = 0xFFFFFFFF;
|
||||
|
||||
unsigned int offset = SZ_HEADER;
|
||||
unsigned int offset = 32;
|
||||
while (offset + 2 <= size) {
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
@ -195,13 +198,13 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
|
||||
// Time (seconds).
|
||||
time += interval;
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
unsigned int depth = bcd2dec (data[offset + 0] & 0x0F) * 100 + bcd2dec (data[offset + 1]);
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
|
||||
// Current gasmix
|
||||
if (ngasmixes) {
|
||||
@ -214,7 +217,7 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
}
|
||||
if (idx != gasmix) {
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
gasmix = idx;
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ cressi_goa_device_send (cressi_goa_device_t *device, unsigned char cmd, const un
|
||||
if (size) {
|
||||
memcpy (packet + 5, data, size);
|
||||
}
|
||||
crc = checksum_crc16_ccitt (packet + 3, size + 2, 0x000, 0x0000);
|
||||
crc = checksum_crc16_ccitt (packet + 3, size + 2, 0x000);
|
||||
packet[5 + size + 0] = (crc ) & 0xFF; // Low
|
||||
packet[5 + size + 1] = (crc >> 8) & 0xFF; // High
|
||||
packet[5 + size + 2] = TRAILER;
|
||||
@ -155,7 +155,7 @@ cressi_goa_device_receive (cressi_goa_device_t *device, unsigned char data[], un
|
||||
|
||||
// Verify the checksum of the packet.
|
||||
unsigned short crc = array_uint16_le (packet + length + 5);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (packet + 3, length + 2, 0x0000, 0x0000);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (packet + 3, length + 2, 0x0000);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected answer checksum.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
@ -203,7 +203,7 @@ cressi_goa_device_download (cressi_goa_device_t *device, dc_buffer_t *buffer, dc
|
||||
|
||||
// Verify the checksum of the packet.
|
||||
unsigned short crc = array_uint16_le (packet + sizeof(packet) - 2);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (packet + 3, sizeof(packet) - 5, 0x0000, 0x0000);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (packet + 3, sizeof(packet) - 5, 0x0000);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected answer checksum.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
@ -485,19 +485,7 @@ cressi_goa_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
|
||||
goto error_free_dive;
|
||||
}
|
||||
|
||||
// Those 5 extra bytes contain the dive mode, which is required for
|
||||
// parsing the dive data. Therefore, insert all 5 bytes again. The
|
||||
// remaining 4 bytes appear to be some 32 bit address.
|
||||
if (!dc_buffer_insert (dive, 2, logbook_data + offset + 2, 5)) {
|
||||
ERROR (abstract->context, "Out of memory.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free_dive;
|
||||
}
|
||||
|
||||
dive_data = dc_buffer_get_data (dive);
|
||||
dive_size = dc_buffer_get_size (dive);
|
||||
|
||||
if (callback && !callback(dive_data, dive_size, dive_data + FP_OFFSET, sizeof(device->fingerprint), userdata))
|
||||
if (callback && !callback(dive_data, dive_size, dive_data + FP_OFFSET - 5, sizeof(device->fingerprint), userdata))
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
cressi_goa_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
cressi_goa_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
cressi_goa_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -28,40 +28,22 @@
|
||||
|
||||
#define ISINSTANCE(parser) dc_device_isinstance((parser), &cressi_goa_parser_vtable)
|
||||
|
||||
#define SZ_HEADER 23
|
||||
#define SZ_HEADER 0x5C
|
||||
|
||||
#define DEPTH 0
|
||||
#define DEPTH2 1
|
||||
#define TIME 2
|
||||
#define TEMPERATURE 3
|
||||
|
||||
#define SCUBA 0
|
||||
#define NITROX 1
|
||||
#define FREEDIVE 2
|
||||
#define GAUGE 3
|
||||
|
||||
#define NGASMIXES 2
|
||||
|
||||
#define UNDEFINED 0xFFFFFFFF
|
||||
|
||||
typedef struct cressi_goa_parser_t cressi_goa_parser_t;
|
||||
|
||||
struct cressi_goa_parser_t {
|
||||
dc_parser_t base;
|
||||
unsigned int model;
|
||||
// Cached fields.
|
||||
unsigned int cached;
|
||||
double maxdepth;
|
||||
};
|
||||
|
||||
typedef struct cressi_goa_layout_t {
|
||||
unsigned int headersize;
|
||||
unsigned int datetime;
|
||||
unsigned int divetime;
|
||||
unsigned int gasmix;
|
||||
unsigned int atmospheric;
|
||||
unsigned int maxdepth;
|
||||
unsigned int avgdepth;
|
||||
unsigned int temperature;
|
||||
} cressi_goa_layout_t;
|
||||
|
||||
static dc_status_t cressi_goa_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -69,64 +51,15 @@ static dc_status_t cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_
|
||||
static const dc_parser_vtable_t cressi_goa_parser_vtable = {
|
||||
sizeof(cressi_goa_parser_t),
|
||||
DC_FAMILY_CRESSI_GOA,
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
cressi_goa_parser_set_data, /* set_data */
|
||||
cressi_goa_parser_get_datetime, /* datetime */
|
||||
cressi_goa_parser_get_field, /* fields */
|
||||
cressi_goa_parser_samples_foreach, /* samples_foreach */
|
||||
NULL /* destroy */
|
||||
};
|
||||
|
||||
static const cressi_goa_layout_t layouts[] = {
|
||||
/* SCUBA */
|
||||
{
|
||||
0x61, /* headersize */
|
||||
0x11, /* datetime */
|
||||
0x19, /* divetime */
|
||||
0x1F, /* gasmix */
|
||||
0x23, /* atmospheric */
|
||||
0x4E, /* maxdepth */
|
||||
0x50, /* avgdepth */
|
||||
0x52, /* temperature */
|
||||
},
|
||||
/* NITROX */
|
||||
{
|
||||
0x61, /* headersize */
|
||||
0x11, /* datetime */
|
||||
0x19, /* divetime */
|
||||
0x1F, /* gasmix */
|
||||
0x23, /* atmospheric */
|
||||
0x4E, /* maxdepth */
|
||||
0x50, /* avgdepth */
|
||||
0x52, /* temperature */
|
||||
},
|
||||
/* FREEDIVE */
|
||||
{
|
||||
0x2B, /* headersize */
|
||||
0x11, /* datetime */
|
||||
0x19, /* divetime */
|
||||
UNDEFINED, /* gasmix */
|
||||
UNDEFINED, /* atmospheric */
|
||||
0x1C, /* maxdepth */
|
||||
UNDEFINED, /* avgdepth */
|
||||
0x1E, /* temperature */
|
||||
},
|
||||
/* GAUGE */
|
||||
{
|
||||
0x2D, /* headersize */
|
||||
0x11, /* datetime */
|
||||
0x19, /* divetime */
|
||||
UNDEFINED, /* gasmix */
|
||||
0x1B, /* atmospheric */
|
||||
0x1D, /* maxdepth */
|
||||
0x1F, /* avgdepth */
|
||||
0x21, /* temperature */
|
||||
},
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
{
|
||||
cressi_goa_parser_t *parser = NULL;
|
||||
|
||||
@ -134,46 +67,47 @@ cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, const unsign
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (cressi_goa_parser_t *) dc_parser_allocate (context, &cressi_goa_parser_vtable, data, size);
|
||||
parser = (cressi_goa_parser_t *) dc_parser_allocate (context, &cressi_goa_parser_vtable);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
parser->model = model;
|
||||
parser->cached = 0;
|
||||
parser->maxdepth = 0.0;
|
||||
|
||||
*out = (dc_parser_t*) parser;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
cressi_goa_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
cressi_goa_parser_t *parser = (cressi_goa_parser_t *) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 0;
|
||||
parser->maxdepth = 0.0;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
if (size < SZ_HEADER)
|
||||
if (abstract->size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int divemode = data[2];
|
||||
if (divemode >= C_ARRAY_SIZE(layouts)) {
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
const cressi_goa_layout_t *layout = &layouts[divemode];
|
||||
|
||||
if (size < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
const unsigned char *p = abstract->data + layout->datetime;
|
||||
const unsigned char *p = abstract->data;
|
||||
|
||||
if (datetime) {
|
||||
datetime->year = array_uint16_le(p);
|
||||
datetime->month = p[2];
|
||||
datetime->day = p[3];
|
||||
datetime->hour = p[4];
|
||||
datetime->minute = p[5];
|
||||
datetime->year = array_uint16_le(p + 0x0C);
|
||||
datetime->month = p[0x0E];
|
||||
datetime->day = p[0x0F];
|
||||
datetime->hour = p[0x10];
|
||||
datetime->minute = p[0x11];
|
||||
datetime->second = 0;
|
||||
datetime->timezone = DC_TIMEZONE_NONE;
|
||||
}
|
||||
@ -184,29 +118,21 @@ cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
static dc_status_t
|
||||
cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
|
||||
{
|
||||
cressi_goa_parser_t *parser = (cressi_goa_parser_t *) abstract;
|
||||
if (abstract->size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
if (size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
if (!parser->cached) {
|
||||
sample_statistics_t statistics = SAMPLE_STATISTICS_INITIALIZER;
|
||||
dc_status_t rc = cressi_goa_parser_samples_foreach (
|
||||
abstract, sample_statistics_cb, &statistics);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
unsigned int divemode = data[2];
|
||||
if (divemode >= C_ARRAY_SIZE(layouts)) {
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
const cressi_goa_layout_t *layout = &layouts[divemode];
|
||||
|
||||
if (size < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int ngasmixes = 0;
|
||||
if (layout->gasmix != UNDEFINED) {
|
||||
for (unsigned int i = 0; i < NGASMIXES; ++i) {
|
||||
if (data[layout->gasmix + 2 * i + 1] == 0)
|
||||
break;
|
||||
ngasmixes++;
|
||||
}
|
||||
parser->cached = 1;
|
||||
parser->maxdepth = statistics.maxdepth;
|
||||
}
|
||||
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
@ -214,55 +140,19 @@ cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
||||
if (value) {
|
||||
switch (type) {
|
||||
case DC_FIELD_DIVETIME:
|
||||
if (layout->divetime == UNDEFINED)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((unsigned int *) value) = array_uint16_le (data + layout->divetime);
|
||||
*((unsigned int *) value) = array_uint16_le (data + 0x14);
|
||||
break;
|
||||
case DC_FIELD_MAXDEPTH:
|
||||
if (layout->maxdepth == UNDEFINED)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((double *) value) = array_uint16_le (data + layout->maxdepth) / 10.0;
|
||||
break;
|
||||
case DC_FIELD_AVGDEPTH:
|
||||
if (layout->avgdepth == UNDEFINED)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((double *) value) = array_uint16_le (data + layout->avgdepth) / 10.0;
|
||||
break;
|
||||
case DC_FIELD_TEMPERATURE_MINIMUM:
|
||||
if (layout->temperature == UNDEFINED)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((double *) value) = array_uint16_le (data + layout->temperature) / 10.0;
|
||||
break;
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
if (layout->atmospheric == UNDEFINED)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((double *) value) = array_uint16_le (data + layout->atmospheric) / 1000.0;
|
||||
*((double *) value) = parser->maxdepth;
|
||||
break;
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
*((unsigned int *) value) = ngasmixes;
|
||||
*((unsigned int *) value) = 2;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->oxygen = data[layout->gasmix + 2 * flags + 1] / 100.0;
|
||||
gasmix->oxygen = data[0x1B + 2 * flags] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
break;
|
||||
case DC_FIELD_DIVEMODE:
|
||||
switch (divemode) {
|
||||
case SCUBA:
|
||||
case NITROX:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_OC;
|
||||
break;
|
||||
case GAUGE:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_GAUGE;
|
||||
break;
|
||||
case FREEDIVE:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_FREEDIVE;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
@ -277,29 +167,12 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
if (size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int divemode = data[2];
|
||||
if (divemode >= C_ARRAY_SIZE(layouts)) {
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
const cressi_goa_layout_t *layout = &layouts[divemode];
|
||||
|
||||
if (size < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int interval = divemode == FREEDIVE ? 2 : 5;
|
||||
|
||||
unsigned int time = 0;
|
||||
unsigned int depth = 0;
|
||||
unsigned int gasmix = 0, gasmix_previous = 0xFFFFFFFF;
|
||||
unsigned int temperature = 0;
|
||||
unsigned int have_temperature = 0;
|
||||
unsigned int complete = 0;
|
||||
unsigned int interval = 5;
|
||||
unsigned int complete = 1;
|
||||
unsigned int gasmix_previous = 0xFFFFFFFF;
|
||||
|
||||
unsigned int offset = layout->headersize;
|
||||
unsigned int offset = SZ_HEADER;
|
||||
while (offset + 2 <= size) {
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
@ -308,46 +181,37 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
unsigned int type = (raw & 0x0003);
|
||||
unsigned int value = (raw & 0xFFFC) >> 2;
|
||||
|
||||
if (type == DEPTH || type == DEPTH2) {
|
||||
depth = (value & 0x07FF);
|
||||
gasmix = (value & 0x0800) >> 11;
|
||||
time += interval;
|
||||
complete = 1;
|
||||
} else if (type == TEMPERATURE) {
|
||||
temperature = value;
|
||||
have_temperature = 1;
|
||||
} else if (type == TIME) {
|
||||
time += value;
|
||||
}
|
||||
|
||||
if (complete) {
|
||||
// Time (seconds).
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Temperature (1/10 °C).
|
||||
if (have_temperature) {
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
have_temperature = 0;
|
||||
}
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Gas change
|
||||
if (divemode == SCUBA || divemode == NITROX) {
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
}
|
||||
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
complete = 0;
|
||||
}
|
||||
|
||||
if (type == DEPTH) {
|
||||
// Depth (1/10 m).
|
||||
unsigned int depth = value & 0x07FF;
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
|
||||
// Gas change.
|
||||
unsigned int gasmix = (value & 0x0800) >> 11;
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
complete = 1;
|
||||
} else if (type == TEMPERATURE) {
|
||||
// Temperature (1/10 °C).
|
||||
sample.temperature = value / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
} else {
|
||||
WARNING(abstract->context, "Unknown sample type %u.", type);
|
||||
}
|
||||
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
|
||||
@ -84,7 +84,7 @@ cressi_leonardo_make_ascii (const unsigned char raw[], unsigned int rsize, unsig
|
||||
array_convert_bin2hex (raw, rsize, ascii + 1, 2 * rsize);
|
||||
|
||||
// Checksum
|
||||
unsigned short crc = checksum_crc16_ccitt (ascii + 1, 2 * rsize, 0xffff, 0x0000);
|
||||
unsigned short crc = checksum_crc16_ccitt (ascii + 1, 2 * rsize, 0xffff);
|
||||
unsigned char checksum[] = {
|
||||
(crc >> 8) & 0xFF, // High
|
||||
(crc ) & 0xFF}; // Low
|
||||
@ -129,7 +129,7 @@ cressi_leonardo_packet (cressi_leonardo_device_t *device, const unsigned char co
|
||||
|
||||
// Verify the checksum of the packet.
|
||||
unsigned short crc = array_uint16_be (checksum);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (answer + 1, asize - 6, 0xffff, 0x0000);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (answer + 1, asize - 6, 0xffff);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected answer checksum.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
@ -372,19 +372,12 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
||||
|
||||
// Verify the checksum.
|
||||
unsigned int csum1 = array_uint16_be (checksum);
|
||||
unsigned int csum2 = checksum_crc16_ccitt (data, SZ_MEMORY, 0xffff, 0x0000);
|
||||
unsigned int csum2 = checksum_crc16_ccitt (data, SZ_MEMORY, 0xffff);
|
||||
if (csum1 != csum2) {
|
||||
ERROR (abstract->context, "Unexpected answer bytes.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = data[0];
|
||||
devinfo.firmware = 0;
|
||||
devinfo.serial = array_uint24_le (data + 1);
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -401,6 +394,13 @@ cressi_leonardo_device_foreach (dc_device_t *abstract, dc_dive_callback_t callba
|
||||
return rc;
|
||||
}
|
||||
|
||||
unsigned char *data = dc_buffer_get_data (buffer);
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = data[0];
|
||||
devinfo.firmware = 0;
|
||||
devinfo.serial = array_uint24_le (data + 1);
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
rc = cressi_leonardo_extract_dives (abstract, dc_buffer_get_data (buffer),
|
||||
dc_buffer_get_size (buffer), callback, userdata);
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
cressi_leonardo_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
cressi_leonardo_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
cressi_leonardo_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -39,6 +39,7 @@ struct cressi_leonardo_parser_t {
|
||||
unsigned int model;
|
||||
};
|
||||
|
||||
static dc_status_t cressi_leonardo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
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);
|
||||
@ -46,9 +47,7 @@ static dc_status_t cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract
|
||||
static const dc_parser_vtable_t cressi_leonardo_parser_vtable = {
|
||||
sizeof(cressi_leonardo_parser_t),
|
||||
DC_FAMILY_CRESSI_LEONARDO,
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
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 */
|
||||
@ -57,7 +56,7 @@ static const dc_parser_vtable_t cressi_leonardo_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
{
|
||||
cressi_leonardo_parser_t *parser = NULL;
|
||||
|
||||
@ -65,7 +64,7 @@ cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, const u
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (cressi_leonardo_parser_t *) dc_parser_allocate (context, &cressi_leonardo_parser_vtable, data, size);
|
||||
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;
|
||||
@ -79,6 +78,13 @@ cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, const u
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cressi_leonardo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -137,7 +143,6 @@ cressi_leonardo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, u
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->oxygen = data[0x19] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -173,9 +178,6 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
|
||||
unsigned int gasmix_previous = 0xFFFFFFFF;
|
||||
unsigned int gasmix = 0;
|
||||
if (parser->model == DRAKE) {
|
||||
gasmix = gasmix_previous;
|
||||
}
|
||||
|
||||
unsigned int offset = SZ_HEADER;
|
||||
while (offset + 2 <= size) {
|
||||
@ -188,12 +190,12 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
|
||||
// Time (seconds).
|
||||
time += surftime;
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
|
||||
offset += 4;
|
||||
} else {
|
||||
@ -203,17 +205,17 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
|
||||
// Time (seconds).
|
||||
time += interval;
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
|
||||
// Gas change.
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
@ -221,13 +223,9 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
if (ascent) {
|
||||
sample.event.type = SAMPLE_EVENT_ASCENT;
|
||||
sample.event.time = 0;
|
||||
if (ascent < 3)
|
||||
// Turn the overly sensitive ascent warnings of this dive computer into info events
|
||||
sample.event.flags = SAMPLE_FLAGS_SEVERITY_INFO;
|
||||
else
|
||||
sample.event.flags = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = ascent;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
}
|
||||
|
||||
offset += 2;
|
||||
|
||||
500
src/deepblu.c
Normal file
500
src/deepblu.c
Normal file
@ -0,0 +1,500 @@
|
||||
/*
|
||||
* Deepblu Cosmiq+ downloading
|
||||
*
|
||||
* Copyright (C) 2019 Linus Torvalds
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include "deepblu.h"
|
||||
#include "context-private.h"
|
||||
#include "device-private.h"
|
||||
#include "array.h"
|
||||
|
||||
// "Write state"
|
||||
#define CMD_SETTIME 0x20 // Send 6 byte date-time, get single-byte 00x00 ack
|
||||
#define CMD_23 0x23 // Send 00/01 byte, get ack back? Some metric/imperial setting?
|
||||
|
||||
// "Read dives"?
|
||||
#define CMD_GETDIVENR 0x40 // Send empty byte, get single-byte number of dives back
|
||||
#define CMD_GETDIVE 0x41 // Send dive number (1-nr) byte, get dive stat length byte back
|
||||
#define RSP_DIVESTAT 0x42 // .. followed by packets of dive stat for that dive of that length
|
||||
#define CMD_GETPROFILE 0x43 // Send dive number (1-nr) byte, get dive profile length BE word back
|
||||
#define RSP_DIVEPROF 0x44 // .. followed by packets of dive profile of that length
|
||||
|
||||
// "Read state"
|
||||
#define CMD_GETTIME 0x50 // Send empty byte, get six-byte bcd date-time back
|
||||
#define CMD_51 0x51 // Send empty byte, get four bytes back (03 dc 00 e3)
|
||||
#define CMD_52 0x52 // Send empty byte, get two bytes back (bf 8d)
|
||||
#define CMD_53 0x53 // Send empty byte, get six bytes back (0e 81 00 03 00 00)
|
||||
#define CMD_54 0x54 // Send empty byte, get byte back (00)
|
||||
#define CMD_55 0x55 // Send empty byte, get byte back (00)
|
||||
#define CMD_56 0x56 // Send empty byte, get byte back (00)
|
||||
#define CMD_57 0x57 // Send empty byte, get byte back (00)
|
||||
#define CMD_58 0x58 // Send empty byte, get byte back (52)
|
||||
#define CMD_59 0x59 // Send empty byte, get six bytes back (00 00 07 00 00 00)
|
||||
// (00 00 00 00 00 00)
|
||||
#define CMD_5a 0x5a // Send empty byte, get six bytes back (23 1b 09 d8 37 c0)
|
||||
#define CMD_5b 0x5b // Send empty byte, get six bytes back (00 21 00 14 00 01)
|
||||
// (00 00 00 14 00 01)
|
||||
#define CMD_5c 0x5c // Send empty byte, get six bytes back (13 88 00 46 20 00)
|
||||
// (13 88 00 3c 15 00)
|
||||
#define CMD_5d 0x5d // Send empty byte, get six bytes back (19 00 23 0C 02 0E)
|
||||
// (14 14 14 0c 01 0e)
|
||||
#define CMD_5f 0x5f // Send empty byte, get six bytes back (00 00 07 00 00 00)
|
||||
|
||||
#define COSMIQ_HDR_SIZE 36
|
||||
|
||||
typedef struct deepblu_device_t {
|
||||
dc_device_t base;
|
||||
dc_iostream_t *iostream;
|
||||
unsigned char fingerprint[COSMIQ_HDR_SIZE];
|
||||
} deepblu_device_t;
|
||||
|
||||
static dc_status_t deepblu_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||
static dc_status_t deepblu_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
||||
static dc_status_t deepblu_device_timesync(dc_device_t *abstract, const dc_datetime_t *datetime);
|
||||
static dc_status_t deepblu_device_close (dc_device_t *abstract);
|
||||
|
||||
static const dc_device_vtable_t deepblu_device_vtable = {
|
||||
sizeof(deepblu_device_t),
|
||||
DC_FAMILY_DEEPBLU,
|
||||
deepblu_device_set_fingerprint, /* set_fingerprint */
|
||||
NULL, /* read */
|
||||
NULL, /* write */
|
||||
NULL, /* dump */
|
||||
deepblu_device_foreach, /* foreach */
|
||||
deepblu_device_timesync, /* timesync */
|
||||
deepblu_device_close, /* close */
|
||||
};
|
||||
|
||||
// Maximum data in a packet. It's actually much
|
||||
// less than this, since BLE packets are small and
|
||||
// with the 7 bytes of headers and final newline
|
||||
// and the HEX encoding, the actual maximum is
|
||||
// just something like 6 bytes.
|
||||
//
|
||||
// But in theory the data could be done over
|
||||
// multiple packets. That doesn't seem to be
|
||||
// the case in anything I've seen so far.
|
||||
//
|
||||
// Pick something small and easy to use for
|
||||
// stack buffers.
|
||||
#define MAX_DATA 20
|
||||
|
||||
static char *
|
||||
write_hex_byte(unsigned char data, char *p)
|
||||
{
|
||||
static const char hex[16] = "0123456789ABCDEF";
|
||||
*p++ = hex[data >> 4];
|
||||
*p++ = hex[data & 0xf];
|
||||
return p;
|
||||
}
|
||||
|
||||
//
|
||||
// Send a cmd packet.
|
||||
//
|
||||
// The format of the cmd on the "wire" is:
|
||||
// - byte '#'
|
||||
// - HEX char of cmd
|
||||
// - HEX char two's complement modular sum of packet data (including cmd/size)
|
||||
// - HEX char size of data as encoded in HEX
|
||||
// - n * HEX char data
|
||||
// - byte '\n'
|
||||
// so you end up having 8 bytes of header/trailer overhead, and two bytes
|
||||
// for every byte of data sent due to the HEX encoding.
|
||||
//
|
||||
static dc_status_t
|
||||
deepblu_send_cmd(deepblu_device_t *device, const unsigned char cmd, const unsigned char data[], size_t size)
|
||||
{
|
||||
char buffer[8+2*MAX_DATA], *p;
|
||||
unsigned char csum;
|
||||
int i;
|
||||
|
||||
if (size > MAX_DATA)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Calculate packet csum
|
||||
csum = cmd + 2*size;
|
||||
for (i = 0; i < size; i++)
|
||||
csum += data[i];
|
||||
csum = -csum;
|
||||
|
||||
// Fill the data buffer
|
||||
p = buffer;
|
||||
*p++ = '#';
|
||||
p = write_hex_byte(cmd, p);
|
||||
p = write_hex_byte(csum, p);
|
||||
p = write_hex_byte(size*2, p);
|
||||
for (i = 0; i < size; i++)
|
||||
p = write_hex_byte(data[i], p);
|
||||
*p++ = '\n';
|
||||
|
||||
// .. and send it out
|
||||
return dc_iostream_write(device->iostream, buffer, p-buffer, NULL);
|
||||
}
|
||||
|
||||
//
|
||||
// Receive one 'line' of data
|
||||
//
|
||||
// The deepblu BLE protocol is ASCII line based and packetized.
|
||||
// Normally one packet is one line, but it looks like the Nordic
|
||||
// Semi BLE chip will sometimes send packets early (some internal
|
||||
// serial buffer timeout?) with incompete data.
|
||||
//
|
||||
// So read packets until you get newline.
|
||||
static dc_status_t
|
||||
deepblu_recv_line(deepblu_device_t *device, unsigned char *buf, size_t size)
|
||||
{
|
||||
while (1) {
|
||||
unsigned char buffer[20];
|
||||
size_t transferred = 0;
|
||||
dc_status_t status;
|
||||
|
||||
status = dc_iostream_read(device->iostream, buffer, sizeof(buffer), &transferred);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR(device->base.context, "Failed to receive Deepblu reply packet.");
|
||||
return status;
|
||||
}
|
||||
if (transferred > size) {
|
||||
ERROR(device->base.context, "Deepblu reply packet with too much data (got %zu, expected %zu)", transferred, size);
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
if (!transferred) {
|
||||
ERROR(device->base.context, "Empty Deepblu reply packet");
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
memcpy(buf, buffer, transferred);
|
||||
buf += transferred;
|
||||
size -= transferred;
|
||||
if (buf[-1] == '\n')
|
||||
break;
|
||||
}
|
||||
buf[-1] = 0;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
hex_nibble(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
read_hex_byte(char *p)
|
||||
{
|
||||
// This is negative if either of the nibbles is invalid
|
||||
return (hex_nibble(p[0]) << 4) | hex_nibble(p[1]);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Receive a reply packet
|
||||
//
|
||||
// The reply packet has the same format as the cmd packet we
|
||||
// send, except the first byte is '$' instead of '#'.
|
||||
static dc_status_t
|
||||
deepblu_recv_data(deepblu_device_t *device, const unsigned char expected, unsigned char *buf, size_t size, size_t *received)
|
||||
{
|
||||
int len, i;
|
||||
dc_status_t status;
|
||||
char buffer[8+2*MAX_DATA];
|
||||
int cmd, csum, ndata;
|
||||
|
||||
status = deepblu_recv_line(device, buffer, sizeof(buffer));
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
// deepblu_recv_line() always zero-terminates the result
|
||||
// if it returned success, and has removed the final newline.
|
||||
len = strlen(buffer);
|
||||
HEXDUMP(device->base.context, DC_LOGLEVEL_DEBUG, "rcv", buffer, len);
|
||||
|
||||
// A valid reply should always be at least 7 characters: the
|
||||
// initial '$' and the three header HEX bytes.
|
||||
if (len < 8 || buffer[0] != '$') {
|
||||
ERROR(device->base.context, "Invalid Deepblu reply packet");
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
cmd = read_hex_byte(buffer+1);
|
||||
csum = read_hex_byte(buffer+3);
|
||||
ndata = read_hex_byte(buffer+5);
|
||||
if ((cmd | csum | ndata) < 0) {
|
||||
ERROR(device->base.context, "non-hex Deepblu reply packet header");
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
// Verify the data length: it's the size of the HEX data,
|
||||
// and should also match the line length we got (the 7
|
||||
// is for the header data we already decoded above).
|
||||
if ((ndata & 1) || ndata != len - 7) {
|
||||
ERROR(device->base.context, "Deepblu reply packet data length does not match (claimed %d, got %d)", ndata, len-7);
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
if (ndata >> 1 > size) {
|
||||
ERROR(device->base.context, "Deepblu reply packet too big for buffer (ndata=%d, size=%zu)", ndata, size);
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
csum += cmd + ndata;
|
||||
|
||||
for (i = 7; i < len; i += 2) {
|
||||
int byte = read_hex_byte(buffer + i);
|
||||
if (byte < 0) {
|
||||
ERROR(device->base.context, "Deepblu reply packet data not valid hex");
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
*buf++ = byte;
|
||||
csum += byte;
|
||||
}
|
||||
|
||||
if (csum & 255) {
|
||||
ERROR(device->base.context, "Deepblu reply packet csum not valid (%x)", csum);
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
*received = ndata >> 1;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Common communication pattern: send a command, expect data back with the same
|
||||
// command byte.
|
||||
static dc_status_t
|
||||
deepblu_send_recv(deepblu_device_t *device, const unsigned char cmd,
|
||||
const unsigned char *data, size_t data_size,
|
||||
unsigned char *result, size_t result_size)
|
||||
{
|
||||
dc_status_t status;
|
||||
size_t got;
|
||||
|
||||
status = deepblu_send_cmd(device, cmd, data, data_size);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
status = deepblu_recv_data(device, cmd, result, result_size, &got);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
if (got != result_size) {
|
||||
ERROR(device->base.context, "Deepblu result size didn't match expected (expected %zu, got %zu)",
|
||||
result_size, got);
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_recv_bulk(deepblu_device_t *device, const unsigned char cmd, unsigned char *buf, size_t len)
|
||||
{
|
||||
while (len) {
|
||||
dc_status_t status;
|
||||
size_t got;
|
||||
|
||||
status = deepblu_recv_data(device, cmd, buf, len, &got);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
if (got > len) {
|
||||
ERROR(device->base.context, "Deepblu bulk receive overflow");
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
buf += got;
|
||||
len -= got;
|
||||
}
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
deepblu_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream)
|
||||
{
|
||||
deepblu_device_t *device;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
device = (deepblu_device_t *) dc_device_allocate (context, &deepblu_device_vtable);
|
||||
if (device == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
device->iostream = iostream;
|
||||
memset(device->fingerprint, 0, sizeof(device->fingerprint));
|
||||
|
||||
*out = (dc_device_t *) device;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
|
||||
{
|
||||
deepblu_device_t *device = (deepblu_device_t *)abstract;
|
||||
|
||||
HEXDUMP(device->base.context, DC_LOGLEVEL_DEBUG, "set_fingerprint", data, size);
|
||||
|
||||
if (size && size != sizeof (device->fingerprint))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (size)
|
||||
memcpy (device->fingerprint, data, sizeof (device->fingerprint));
|
||||
else
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static unsigned char bcd(int val)
|
||||
{
|
||||
if (val >= 0 && val < 100) {
|
||||
int high = val / 10;
|
||||
int low = val % 10;
|
||||
return (high << 4) | low;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_device_timesync(dc_device_t *abstract, const dc_datetime_t *datetime)
|
||||
{
|
||||
deepblu_device_t *device = (deepblu_device_t *)abstract;
|
||||
unsigned char result[1], data[6];
|
||||
dc_status_t status;
|
||||
size_t len;
|
||||
|
||||
data[0] = bcd(datetime->year - 2000);
|
||||
data[1] = bcd(datetime->month);
|
||||
data[2] = bcd(datetime->day);
|
||||
data[3] = bcd(datetime->hour);
|
||||
data[4] = bcd(datetime->minute);
|
||||
data[5] = bcd(datetime->second);
|
||||
|
||||
// Maybe also check that we received one zero byte (ack?)
|
||||
return deepblu_send_recv(device, CMD_SETTIME,
|
||||
data, sizeof(data),
|
||||
result, sizeof(result));
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_device_close (dc_device_t *abstract)
|
||||
{
|
||||
deepblu_device_t *device = (deepblu_device_t *) abstract;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static const char zero[MAX_DATA];
|
||||
|
||||
static dc_status_t
|
||||
deepblu_download_dive(deepblu_device_t *device, unsigned char nr, dc_dive_callback_t callback, void *userdata)
|
||||
{
|
||||
unsigned char header_len;
|
||||
unsigned char profilebytes[2];
|
||||
unsigned int profile_len;
|
||||
dc_status_t status;
|
||||
char header[256];
|
||||
unsigned char *profile;
|
||||
|
||||
status = deepblu_send_recv(device, CMD_GETDIVE, &nr, 1, &header_len, 1);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
status = deepblu_recv_bulk(device, RSP_DIVESTAT, header, header_len);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
memset(header + header_len, 0, 256 - header_len);
|
||||
|
||||
/* The header is the fingerprint. If we've already seen this header, we're done */
|
||||
if (memcmp(header, device->fingerprint, sizeof (device->fingerprint)) == 0)
|
||||
return DC_STATUS_DONE;
|
||||
|
||||
status = deepblu_send_recv(device, CMD_GETPROFILE, &nr, 1, profilebytes, sizeof(profilebytes));
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
profile_len = (profilebytes[0] << 8) | profilebytes[1];
|
||||
|
||||
profile = malloc(256 + profile_len);
|
||||
if (!profile) {
|
||||
ERROR (device->base.context, "Insufficient buffer space available.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// We make the dive data be 256 bytes of header, followed by the profile data
|
||||
memcpy(profile, header, 256);
|
||||
|
||||
status = deepblu_recv_bulk(device, RSP_DIVEPROF, profile+256, profile_len);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (callback) {
|
||||
if (!callback(profile, profile_len+256, header, header_len, userdata))
|
||||
return DC_STATUS_DONE;
|
||||
}
|
||||
free(profile);
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
|
||||
{
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
deepblu_device_t *device = (deepblu_device_t *) abstract;
|
||||
unsigned char nrdives, val;
|
||||
dc_status_t status;
|
||||
int i;
|
||||
|
||||
val = 0;
|
||||
status = deepblu_send_recv(device, CMD_GETDIVENR, &val, 1, &nrdives, 1);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (!nrdives)
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
progress.maximum = nrdives;
|
||||
progress.current = 0;
|
||||
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
for (i = 1; i <= nrdives; i++) {
|
||||
if (device_is_cancelled(abstract)) {
|
||||
dc_status_set_error(&status, DC_STATUS_CANCELLED);
|
||||
break;
|
||||
}
|
||||
|
||||
status = deepblu_download_dive(device, i, callback, userdata);
|
||||
switch (status) {
|
||||
case DC_STATUS_DONE:
|
||||
i = nrdives;
|
||||
break;
|
||||
case DC_STATUS_SUCCESS:
|
||||
break;
|
||||
default:
|
||||
return status;
|
||||
}
|
||||
progress.current = i;
|
||||
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
* Deepblu Cosmiq+ downloading/parsing
|
||||
*
|
||||
* Copyright (C) 2023 Janice McLaughlin
|
||||
* Copyright (C) 2018 Linus Torvalds
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -18,10 +18,9 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
// test 01
|
||||
|
||||
#ifndef PELAGIC_I330R_H
|
||||
#define PELAGIC_I330R_H
|
||||
#ifndef DEEPBLU_H
|
||||
#define DEEPBLU_H
|
||||
|
||||
#include <libdivecomputer/context.h>
|
||||
#include <libdivecomputer/iostream.h>
|
||||
@ -33,9 +32,12 @@ extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
dc_status_t
|
||||
pelagic_i330r_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
|
||||
deepblu_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
deepblu_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* PELAGIC_I330R_H */
|
||||
#endif /* DEEPBLU_H */
|
||||
@ -1,548 +0,0 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2019 Linus Torvalds
|
||||
* Copyright (C) 2022 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 <stdlib.h>
|
||||
|
||||
#include "deepblu_cosmiq.h"
|
||||
#include "context-private.h"
|
||||
#include "device-private.h"
|
||||
#include "platform.h"
|
||||
#include "checksum.h"
|
||||
#include "array.h"
|
||||
|
||||
// Maximum data in a packet. It's actually much
|
||||
// less than this, since BLE packets are small and
|
||||
// with the 7 bytes of headers and final newline
|
||||
// and the HEX encoding, the actual maximum is
|
||||
// just something like 6 bytes.
|
||||
//
|
||||
// But in theory the data could be done over
|
||||
// multiple packets. That doesn't seem to be
|
||||
// the case in anything I've seen so far.
|
||||
//
|
||||
// Pick something small and easy to use for
|
||||
// stack buffers.
|
||||
#define MAX_DATA 20
|
||||
|
||||
#define SZ_HEADER 36
|
||||
|
||||
#define FP_OFFSET 6
|
||||
#define FP_SIZE 6
|
||||
|
||||
#define CMD_SET_DATETIME 0x20
|
||||
|
||||
#define CMD_DIVE_COUNT 0x40
|
||||
#define CMD_DIVE_HEADER 0x41
|
||||
#define CMD_DIVE_HEADER_DATA 0x42
|
||||
#define CMD_DIVE_PROFILE 0x43
|
||||
#define CMD_DIVE_PROFILE_DATA 0x44
|
||||
|
||||
#define CMD_SYSTEM_FW 0x58
|
||||
#define CMD_SYSTEM_MAC 0x5A
|
||||
|
||||
#define NSTEPS 1000
|
||||
#define STEP(i,n) (NSTEPS * (i) / (n))
|
||||
|
||||
typedef struct deepblu_cosmiq_device_t {
|
||||
dc_device_t base;
|
||||
dc_iostream_t *iostream;
|
||||
unsigned char fingerprint[FP_SIZE];
|
||||
} deepblu_cosmiq_device_t;
|
||||
|
||||
static dc_status_t deepblu_cosmiq_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||
static dc_status_t deepblu_cosmiq_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
||||
static dc_status_t deepblu_cosmiq_device_timesync(dc_device_t *abstract, const dc_datetime_t *datetime);
|
||||
|
||||
static const dc_device_vtable_t deepblu_cosmiq_device_vtable = {
|
||||
sizeof(deepblu_cosmiq_device_t),
|
||||
DC_FAMILY_DEEPBLU_COSMIQ,
|
||||
deepblu_cosmiq_device_set_fingerprint, /* set_fingerprint */
|
||||
NULL, /* read */
|
||||
NULL, /* write */
|
||||
NULL, /* dump */
|
||||
deepblu_cosmiq_device_foreach, /* foreach */
|
||||
deepblu_cosmiq_device_timesync, /* timesync */
|
||||
NULL, /* close */
|
||||
};
|
||||
|
||||
//
|
||||
// Send a cmd packet.
|
||||
//
|
||||
// The format of the cmd on the "wire" is:
|
||||
// - byte '#'
|
||||
// - HEX char of cmd
|
||||
// - HEX char two's complement modular sum of packet data (including cmd/size)
|
||||
// - HEX char size of data as encoded in HEX
|
||||
// - n * HEX char data
|
||||
// - byte '\n'
|
||||
// so you end up having 8 bytes of header/trailer overhead, and two bytes
|
||||
// for every byte of data sent due to the HEX encoding.
|
||||
//
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_send (deepblu_cosmiq_device_t *device, const unsigned char cmd, const unsigned char data[], size_t size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
if (size > MAX_DATA)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (device_is_cancelled (abstract))
|
||||
return DC_STATUS_CANCELLED;
|
||||
|
||||
// Build the packet.
|
||||
unsigned char csum = ~checksum_add_uint8 (data, size, cmd + 2 * size) + 1;
|
||||
unsigned char raw[3 + MAX_DATA] = {
|
||||
cmd,
|
||||
csum,
|
||||
2 * size
|
||||
};
|
||||
if (size) {
|
||||
memcpy (raw + 3, data, size);
|
||||
}
|
||||
unsigned char packet[1 + 2 * (3 + MAX_DATA) + 1] = {0};
|
||||
packet[0] = '#';
|
||||
array_convert_bin2hex (raw, 3 + size, packet + 1, 2 * (3 + size));
|
||||
packet[1 + 2 * (3 + size)] = '\n';
|
||||
|
||||
HEXDUMP (device->base.context, DC_LOGLEVEL_DEBUG, "cmd", raw, 3 + size);
|
||||
|
||||
// Send the command.
|
||||
status = dc_iostream_write (device->iostream, packet, 2 + 2 * (3 + size), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (device->base.context, "Failed to send the command.");
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Receive one 'line' of data
|
||||
//
|
||||
// The deepblu BLE protocol is ASCII line based and packetized.
|
||||
// Normally one packet is one line, but it looks like the Nordic
|
||||
// Semi BLE chip will sometimes send packets early (some internal
|
||||
// serial buffer timeout?) with incompete data.
|
||||
//
|
||||
// So read packets until you get newline.
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_recv_line (deepblu_cosmiq_device_t *device, unsigned char data[], size_t size, size_t *actual)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
size_t nbytes = 0;
|
||||
|
||||
while (1) {
|
||||
unsigned char buffer[20] = {0};
|
||||
size_t transferred = 0;
|
||||
|
||||
status = dc_iostream_read (device->iostream, buffer, sizeof(buffer), &transferred);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (device->base.context, "Failed to receive the reply packet.");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (transferred < 1) {
|
||||
ERROR (device->base.context, "Empty reply packet received.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Append the payload data to the output buffer. If the output
|
||||
// buffer is too small, the error is not reported immediately
|
||||
// but delayed until all packets have been received.
|
||||
if (nbytes < size) {
|
||||
size_t n = transferred;
|
||||
if (nbytes + n > size) {
|
||||
n = size - nbytes;
|
||||
}
|
||||
memcpy(data + nbytes, buffer, n);
|
||||
}
|
||||
nbytes += transferred;
|
||||
|
||||
// Last packet?
|
||||
if (buffer[transferred - 1] == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
// Verify the expected number of bytes.
|
||||
if (nbytes > size) {
|
||||
ERROR (device->base.context, "Unexpected number of bytes received (" DC_PRINTF_SIZE " " DC_PRINTF_SIZE ").", nbytes, size);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (actual)
|
||||
*actual = nbytes;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Receive a reply packet
|
||||
//
|
||||
// The reply packet has the same format as the cmd packet we
|
||||
// send, except the first byte is '$' instead of '#'.
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_recv (deepblu_cosmiq_device_t *device, const unsigned char cmd, unsigned char data[], size_t size, size_t *actual)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
unsigned char packet[1 + 2 * (3 + MAX_DATA) + 1] = {0};
|
||||
|
||||
size_t transferred = 0;
|
||||
status = deepblu_cosmiq_recv_line (device, packet, sizeof(packet), &transferred);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (transferred < 8 || (transferred % 2) != 0) {
|
||||
ERROR (device->base.context, "Unexpected packet length (" DC_PRINTF_SIZE ").", transferred);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (packet[0] != '$' || packet[transferred - 1] != '\n') {
|
||||
ERROR (device->base.context, "Unexpected packet start/end byte.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
size_t length = transferred - 2;
|
||||
|
||||
unsigned char raw[3 + MAX_DATA] = {0};
|
||||
if (array_convert_hex2bin (packet + 1, length, raw, length / 2) != 0) {
|
||||
ERROR (device->base.context, "Unexpected packet data.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
length /= 2;
|
||||
|
||||
HEXDUMP (device->base.context, DC_LOGLEVEL_DEBUG, "rcv", raw, length);
|
||||
|
||||
unsigned char rsp = raw[0];
|
||||
if (rsp != cmd) {
|
||||
ERROR (device->base.context, "Unexpected packet command byte (%02x)", rsp);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
unsigned int n = raw[2];
|
||||
if ((n % 2) != 0 || n != transferred - 8) {
|
||||
ERROR (device->base.context, "Unexpected packet length (%u)", n);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
unsigned char csum = checksum_add_uint8 (raw, length, 0);
|
||||
if (csum != 0) {
|
||||
ERROR (device->base.context, "Unexpected packet checksum (%02x).", csum);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
length -= 3;
|
||||
|
||||
if (length > size) {
|
||||
ERROR (device->base.context, "Unexpected number of bytes received (" DC_PRINTF_SIZE " " DC_PRINTF_SIZE ").", length, size);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
memcpy (data, raw + 3, length);
|
||||
|
||||
if (actual)
|
||||
*actual = length;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_transfer (deepblu_cosmiq_device_t *device, const unsigned char cmd,
|
||||
const unsigned char input[], size_t isize,
|
||||
unsigned char output[], size_t osize)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
|
||||
status = deepblu_cosmiq_send (device, cmd, input, isize);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
size_t transferred = 0;
|
||||
status = deepblu_cosmiq_recv (device, cmd, output, osize, &transferred);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (transferred != osize) {
|
||||
ERROR (device->base.context, "Unexpected number of bytes received (" DC_PRINTF_SIZE " " DC_PRINTF_SIZE ").", osize, transferred);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_recv_bulk (deepblu_cosmiq_device_t *device, dc_event_progress_t *progress, const unsigned char cmd, unsigned char data[], size_t size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
const unsigned int initial = progress ? progress->current : 0;
|
||||
|
||||
size_t nbytes = 0;
|
||||
while (nbytes < size) {
|
||||
size_t transferred = 0;
|
||||
status = deepblu_cosmiq_recv (device, cmd, data + nbytes, size - nbytes, &transferred);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
nbytes += transferred;
|
||||
|
||||
// Update and emit a progress event.
|
||||
if (progress) {
|
||||
progress->current = initial + STEP(nbytes, size);
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
|
||||
}
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
deepblu_cosmiq_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
deepblu_cosmiq_device_t *device = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
device = (deepblu_cosmiq_device_t *) dc_device_allocate (context, &deepblu_cosmiq_device_vtable);
|
||||
if (device == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
device->iostream = iostream;
|
||||
memset (device->fingerprint, 0, sizeof(device->fingerprint));
|
||||
|
||||
// Set the timeout for receiving data (1000ms).
|
||||
status = dc_iostream_set_timeout (device->iostream, 1000);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the timeout.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
dc_iostream_purge (device->iostream, DC_DIRECTION_ALL);
|
||||
|
||||
*out = (dc_device_t *) device;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free:
|
||||
dc_device_deallocate ((dc_device_t *) device);
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
|
||||
{
|
||||
deepblu_cosmiq_device_t *device = (deepblu_cosmiq_device_t *)abstract;
|
||||
|
||||
if (size && size != sizeof (device->fingerprint))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (size)
|
||||
memcpy (device->fingerprint, data, sizeof (device->fingerprint));
|
||||
else
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
deepblu_cosmiq_device_t *device = (deepblu_cosmiq_device_t *) abstract;
|
||||
const unsigned char zero = 0;
|
||||
|
||||
// Enable progress notifications.
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
// Read the firmware version.
|
||||
unsigned char fw[1] = {0};
|
||||
status = deepblu_cosmiq_transfer (device, CMD_SYSTEM_FW, &zero, 1, fw, sizeof(fw));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the firmware version.");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// Read the MAC address.
|
||||
unsigned char mac[6] = {0};
|
||||
status = deepblu_cosmiq_transfer (device, CMD_SYSTEM_MAC, &zero, 1, mac, sizeof(mac));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the MAC address.");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = 0;
|
||||
devinfo.firmware = fw[0] & 0x3F;
|
||||
devinfo.serial = array_uint32_le (mac);
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
unsigned char ndives = 0;
|
||||
status = deepblu_cosmiq_transfer (device, CMD_DIVE_COUNT, &zero, 1, &ndives, 1);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the number of dives.");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current = (ndives == 0 ? 1 : 0) * NSTEPS;
|
||||
progress.maximum = (ndives + 1) * NSTEPS;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
if (ndives == 0) {
|
||||
status = DC_STATUS_SUCCESS;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
unsigned char *headers = malloc (ndives * SZ_HEADER);
|
||||
if (headers == NULL) {
|
||||
ERROR (abstract->context, "Failed to allocate memory.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
unsigned int count = 0;
|
||||
for (unsigned int i = 0; i < ndives; ++i) {
|
||||
unsigned char number = i + 1;
|
||||
|
||||
unsigned char len = 0;
|
||||
status = deepblu_cosmiq_transfer (device, CMD_DIVE_HEADER, &number, 1, &len, 1);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the dive header.");
|
||||
goto error_free_headers;
|
||||
}
|
||||
|
||||
if (len != SZ_HEADER) {
|
||||
status = DC_STATUS_PROTOCOL;
|
||||
goto error_free_headers;
|
||||
}
|
||||
|
||||
status = deepblu_cosmiq_recv_bulk (device, NULL, CMD_DIVE_HEADER_DATA, headers + i * SZ_HEADER, SZ_HEADER);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the dive header.");
|
||||
goto error_free_headers;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current = STEP(i + 1, ndives);
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
if (memcmp (headers + i * SZ_HEADER + FP_OFFSET, device->fingerprint, sizeof (device->fingerprint)) == 0)
|
||||
break;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current = 1 * NSTEPS;
|
||||
progress.maximum = (count + 1) * NSTEPS;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
// Allocate memory for the dive.
|
||||
dc_buffer_t *dive = dc_buffer_new (4096);
|
||||
if (dive == NULL) {
|
||||
ERROR (abstract->context, "Failed to allocate memory.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free_headers;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
unsigned char number = i + 1;
|
||||
|
||||
unsigned char rsp_len[2] = {0};
|
||||
status = deepblu_cosmiq_transfer (device, CMD_DIVE_PROFILE, &number, 1, rsp_len, sizeof(rsp_len));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the dive profile.");
|
||||
goto error_free_dive;
|
||||
}
|
||||
|
||||
unsigned int len = array_uint16_be (rsp_len);
|
||||
|
||||
// Erase the buffer.
|
||||
dc_buffer_clear (dive);
|
||||
|
||||
// Allocate memory for the dive.
|
||||
if (!dc_buffer_resize (dive, len + SZ_HEADER)) {
|
||||
ERROR (abstract->context, "Failed to allocate memory.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free_dive;
|
||||
}
|
||||
|
||||
// Cache the pointer.
|
||||
unsigned char *data = dc_buffer_get_data (dive);
|
||||
|
||||
memcpy (data, headers + i * SZ_HEADER, SZ_HEADER);
|
||||
|
||||
status = deepblu_cosmiq_recv_bulk (device, &progress, CMD_DIVE_PROFILE_DATA, data + SZ_HEADER, len);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the dive profile.");
|
||||
goto error_free_dive;
|
||||
}
|
||||
|
||||
if (callback && !callback (data, len + SZ_HEADER, data + FP_OFFSET, FP_SIZE, userdata))
|
||||
break;
|
||||
}
|
||||
|
||||
error_free_dive:
|
||||
dc_buffer_free (dive);
|
||||
error_free_headers:
|
||||
free (headers);
|
||||
error_exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
deepblu_cosmiq_device_t *device = (deepblu_cosmiq_device_t *) abstract;
|
||||
|
||||
if (datetime->year < 2000) {
|
||||
ERROR (abstract->context, "Invalid date/time value specified.");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
const unsigned char cmd[6] = {
|
||||
dec2bcd(datetime->year - 2000),
|
||||
dec2bcd(datetime->month),
|
||||
dec2bcd(datetime->day),
|
||||
dec2bcd(datetime->hour),
|
||||
dec2bcd(datetime->minute),
|
||||
dec2bcd(datetime->second)};
|
||||
unsigned char rsp[1] = {0};
|
||||
status = deepblu_cosmiq_transfer (device, CMD_SET_DATETIME,
|
||||
cmd, sizeof(cmd), rsp, sizeof(rsp));
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2018 Linus Torvalds
|
||||
* Copyright (C) 2022 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 DEEPBLU_COSMIQ_H
|
||||
#define DEEPBLU_COSMIQ_H
|
||||
|
||||
#include <libdivecomputer/context.h>
|
||||
#include <libdivecomputer/iostream.h>
|
||||
#include <libdivecomputer/device.h>
|
||||
#include <libdivecomputer/parser.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
dc_status_t
|
||||
deepblu_cosmiq_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
deepblu_cosmiq_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* DEEPBLU_COSMIQ_H */
|
||||
@ -1,211 +0,0 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2019 Linus Torvalds
|
||||
* Copyright (C) 2022 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 <libdivecomputer/units.h>
|
||||
|
||||
#include "deepblu_cosmiq.h"
|
||||
#include "context-private.h"
|
||||
#include "parser-private.h"
|
||||
#include "array.h"
|
||||
|
||||
#define SCUBA 2
|
||||
#define GAUGE 3
|
||||
#define FREEDIVE 4
|
||||
|
||||
#define SZ_HEADER 36
|
||||
#define SZ_SAMPLE 4
|
||||
|
||||
typedef struct deepblu_cosmiq_parser_t {
|
||||
dc_parser_t base;
|
||||
double hydrostatic;
|
||||
} deepblu_cosmiq_parser_t;
|
||||
|
||||
static dc_status_t deepblu_cosmiq_parser_set_density (dc_parser_t *abstract, double density);
|
||||
static dc_status_t deepblu_cosmiq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t deepblu_cosmiq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t deepblu_cosmiq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
|
||||
static const dc_parser_vtable_t deepblu_cosmiq_parser_vtable = {
|
||||
sizeof(deepblu_cosmiq_parser_t),
|
||||
DC_FAMILY_DEEPBLU_COSMIQ,
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
deepblu_cosmiq_parser_set_density, /* set_density */
|
||||
deepblu_cosmiq_parser_get_datetime, /* datetime */
|
||||
deepblu_cosmiq_parser_get_field, /* fields */
|
||||
deepblu_cosmiq_parser_samples_foreach, /* samples_foreach */
|
||||
NULL /* destroy */
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
deepblu_cosmiq_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
deepblu_cosmiq_parser_t *parser = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (deepblu_cosmiq_parser_t *) dc_parser_allocate (context, &deepblu_cosmiq_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
parser->hydrostatic = DEF_DENSITY_SALT * GRAVITY;
|
||||
|
||||
*out = (dc_parser_t *) parser;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_parser_set_density (dc_parser_t *abstract, double density)
|
||||
{
|
||||
deepblu_cosmiq_parser_t *parser = (deepblu_cosmiq_parser_t *) abstract;
|
||||
|
||||
parser->hydrostatic = density * GRAVITY;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
if (size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
if (datetime) {
|
||||
datetime->year = array_uint16_le(data + 6);
|
||||
datetime->day = data[8];
|
||||
datetime->month = data[9];
|
||||
datetime->minute = data[10];
|
||||
datetime->hour = data[11];
|
||||
datetime->second = 0;
|
||||
datetime->timezone = DC_TIMEZONE_NONE;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
|
||||
{
|
||||
deepblu_cosmiq_parser_t *parser = (deepblu_cosmiq_parser_t *) abstract;
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
|
||||
if (size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int mode = data[2];
|
||||
unsigned int atmospheric = array_uint16_le (data + 4) & 0x1FFF;
|
||||
|
||||
if (value) {
|
||||
switch (type) {
|
||||
case DC_FIELD_DIVETIME:
|
||||
if (mode == SCUBA || mode == GAUGE)
|
||||
*((unsigned int *) value) = array_uint16_le(data + 12) * 60;
|
||||
else
|
||||
*((unsigned int *) value) = array_uint16_le(data + 12);
|
||||
break;
|
||||
case DC_FIELD_MAXDEPTH:
|
||||
*((double *) value) = (signed int) (array_uint16_le (data + 22) - atmospheric) * (BAR / 1000.0) / parser->hydrostatic;
|
||||
break;
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
*((unsigned int *) value) = mode == SCUBA;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->oxygen = data[3] / 100.0;
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
break;
|
||||
case DC_FIELD_DIVEMODE:
|
||||
switch (mode) {
|
||||
case SCUBA:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_OC;
|
||||
break;
|
||||
case GAUGE:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_GAUGE;
|
||||
break;
|
||||
case FREEDIVE:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_FREEDIVE;
|
||||
break;
|
||||
default:
|
||||
ERROR (abstract->context, "Unknown activity type '%02x'", mode);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
*((double *) value) = atmospheric / 1000.0;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
deepblu_cosmiq_parser_t *parser = (deepblu_cosmiq_parser_t *) abstract;
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
if (size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int interval = data[26];
|
||||
unsigned int atmospheric = array_uint16_le (data + 4) & 0x1FFF;
|
||||
|
||||
unsigned int time = 0;
|
||||
unsigned int offset = SZ_HEADER;
|
||||
while (offset + SZ_SAMPLE <= size) {
|
||||
dc_sample_value_t sample = {0};
|
||||
unsigned int temperature = array_uint16_le(data + offset + 0);
|
||||
unsigned int depth = array_uint16_le(data + offset + 2);
|
||||
offset += SZ_SAMPLE;
|
||||
|
||||
time += interval;
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
sample.depth = (signed int) (depth - atmospheric) * (BAR / 1000.0) / parser->hydrostatic;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
278
src/deepblu_parser.c
Normal file
278
src/deepblu_parser.c
Normal file
@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Deeplu Cosmiq+ parsing
|
||||
*
|
||||
* Copyright (C) 2019 Linus Torvalds
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "deepblu.h"
|
||||
#include "context-private.h"
|
||||
#include "parser-private.h"
|
||||
#include "array.h"
|
||||
#include "field-cache.h"
|
||||
|
||||
#define C_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
|
||||
|
||||
#define MAXFIELDS 128
|
||||
|
||||
struct msg_desc;
|
||||
|
||||
typedef struct deepblu_parser_t {
|
||||
dc_parser_t base;
|
||||
|
||||
dc_sample_callback_t callback;
|
||||
void *userdata;
|
||||
|
||||
// 20 sec for scuba, 1 sec for freedives
|
||||
int sample_interval;
|
||||
|
||||
// Common fields
|
||||
struct dc_field_cache cache;
|
||||
} deepblu_parser_t;
|
||||
|
||||
static dc_status_t deepblu_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t deepblu_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t deepblu_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t deepblu_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
|
||||
static const dc_parser_vtable_t deepblu_parser_vtable = {
|
||||
sizeof(deepblu_parser_t),
|
||||
DC_FAMILY_DEEPBLU,
|
||||
deepblu_parser_set_data, /* set_data */
|
||||
deepblu_parser_get_datetime, /* datetime */
|
||||
deepblu_parser_get_field, /* fields */
|
||||
deepblu_parser_samples_foreach, /* samples_foreach */
|
||||
NULL /* destroy */
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
deepblu_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
{
|
||||
deepblu_parser_t *parser = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (deepblu_parser_t *) dc_parser_allocate (context, &deepblu_parser_vtable);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
*out = (dc_parser_t *) parser;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static double
|
||||
pressure_to_depth(unsigned int mbar)
|
||||
{
|
||||
// Specific weight of seawater (millibar to cm)
|
||||
const double specific_weight = 1.024 * 0.980665;
|
||||
|
||||
// Absolute pressure, subtract surface pressure
|
||||
if (mbar < 1013)
|
||||
return 0.0;
|
||||
mbar -= 1013;
|
||||
return mbar / specific_weight / 100.0;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
deepblu_parser_t *deepblu = (deepblu_parser_t *) abstract;
|
||||
const unsigned char *hdr = data;
|
||||
const unsigned char *profile = data + 256;
|
||||
unsigned int divetime, maxpressure;
|
||||
dc_gasmix_t gasmix = {0, };
|
||||
|
||||
if (size < 256)
|
||||
return DC_STATUS_IO;
|
||||
|
||||
deepblu->callback = NULL;
|
||||
deepblu->userdata = NULL;
|
||||
memset(&deepblu->cache, 0, sizeof(deepblu->cache));
|
||||
|
||||
// LE16 at 0 is 'dive number'
|
||||
|
||||
// LE16 at 12 is the dive time
|
||||
// It's in seconds for freedives, minutes for scuba/gauge
|
||||
divetime = hdr[12] + 256*hdr[13];
|
||||
|
||||
// Byte at 2 is 'activity type' (2 = scuba, 3 = gauge, 4 = freedive)
|
||||
// Byte at 3 is O2 percentage
|
||||
switch (data[2]) {
|
||||
case 2:
|
||||
// SCUBA - divetime in minutes
|
||||
divetime *= 60;
|
||||
gasmix.oxygen = data[3] / 100.0;
|
||||
DC_ASSIGN_IDX(deepblu->cache, GASMIX, 0, gasmix);
|
||||
DC_ASSIGN_FIELD(deepblu->cache, GASMIX_COUNT, 1);
|
||||
DC_ASSIGN_FIELD(deepblu->cache, DIVEMODE, DC_DIVEMODE_OC);
|
||||
break;
|
||||
case 3:
|
||||
// GAUGE - divetime in minutes
|
||||
divetime *= 60;
|
||||
DC_ASSIGN_FIELD(deepblu->cache, DIVEMODE, DC_DIVEMODE_GAUGE);
|
||||
break;
|
||||
case 4:
|
||||
// FREEDIVE - divetime in seconds
|
||||
DC_ASSIGN_FIELD(deepblu->cache, DIVEMODE, DC_DIVEMODE_FREEDIVE);
|
||||
deepblu->sample_interval = 1;
|
||||
break;
|
||||
default:
|
||||
ERROR (abstract->context, "Deepblu: unknown activity type '%02x'", data[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
// Seems to be fixed at 20s for scuba, 1s for freedive
|
||||
deepblu->sample_interval = hdr[26];
|
||||
|
||||
maxpressure = hdr[22] + 256*hdr[23]; // Maxpressure in millibar
|
||||
|
||||
DC_ASSIGN_FIELD(deepblu->cache, DIVETIME, divetime);
|
||||
DC_ASSIGN_FIELD(deepblu->cache, MAXDEPTH, pressure_to_depth(maxpressure));
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// The layout of the header in the 'data' is
|
||||
// 0: LE16 dive number
|
||||
// 2: dive type byte?
|
||||
// 3: O2 percentage byte
|
||||
// 4: unknown
|
||||
// 5: unknown
|
||||
// 6: LE16 year
|
||||
// 8: day of month
|
||||
// 9: month
|
||||
// 10: minute
|
||||
// 11: hour
|
||||
// 12: LE16 dive time
|
||||
// 14: LE16 ??
|
||||
// 16: LE16 surface pressure?
|
||||
// 18: LE16 ??
|
||||
// 20: LE16 ??
|
||||
// 22: LE16 max depth pressure
|
||||
// 24: LE16 water temp
|
||||
// 26: LE16 ??
|
||||
// 28: LE16 ??
|
||||
// 30: LE16 ??
|
||||
// 32: LE16 ??
|
||||
// 34: LE16 ??
|
||||
static dc_status_t
|
||||
deepblu_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
deepblu_parser_t *deepblu = (deepblu_parser_t *) abstract;
|
||||
const unsigned char *data = deepblu->base.data;
|
||||
int len = deepblu->base.size;
|
||||
|
||||
if (len < 256)
|
||||
return DC_STATUS_IO;
|
||||
datetime->year = data[6] + (data[7] << 8);
|
||||
datetime->day = data[8];
|
||||
datetime->month = data[9];
|
||||
datetime->minute = data[10];
|
||||
datetime->hour = data[11];
|
||||
datetime->second = 0;
|
||||
datetime->timezone = DC_TIMEZONE_NONE;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
|
||||
{
|
||||
deepblu_parser_t *deepblu = (deepblu_parser_t *) abstract;
|
||||
|
||||
if (!value)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
/* This whole sequence should be standardized */
|
||||
if (!(deepblu->cache.initialized & (1 << type)))
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
|
||||
switch (type) {
|
||||
case DC_FIELD_DIVETIME:
|
||||
return DC_FIELD_VALUE(deepblu->cache, value, DIVETIME);
|
||||
case DC_FIELD_MAXDEPTH:
|
||||
return DC_FIELD_VALUE(deepblu->cache, value, MAXDEPTH);
|
||||
case DC_FIELD_AVGDEPTH:
|
||||
return DC_FIELD_VALUE(deepblu->cache, value, AVGDEPTH);
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
case DC_FIELD_TANK_COUNT:
|
||||
return DC_FIELD_VALUE(deepblu->cache, value, GASMIX_COUNT);
|
||||
case DC_FIELD_GASMIX:
|
||||
if (flags >= MAXGASES)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
return DC_FIELD_INDEX(deepblu->cache, value, GASMIX, flags);
|
||||
case DC_FIELD_SALINITY:
|
||||
return DC_FIELD_VALUE(deepblu->cache, value, SALINITY);
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
return DC_FIELD_VALUE(deepblu->cache, value, ATMOSPHERIC);
|
||||
case DC_FIELD_DIVEMODE:
|
||||
return DC_FIELD_VALUE(deepblu->cache, value, DIVEMODE);
|
||||
case DC_FIELD_TANK:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
case DC_FIELD_STRING:
|
||||
return dc_field_get_string(&deepblu->cache, flags, (dc_field_string_t *)value);
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
deepblu_parser_t *deepblu = (deepblu_parser_t *) abstract;
|
||||
const unsigned char *data = deepblu->base.data;
|
||||
int len = deepblu->base.size, i;
|
||||
|
||||
deepblu->callback = callback;
|
||||
deepblu->userdata = userdata;
|
||||
|
||||
// Skip the header information
|
||||
if (len < 256)
|
||||
return DC_STATUS_IO;
|
||||
data += 256;
|
||||
len -= 256;
|
||||
|
||||
// The rest should be samples every 20s with temperature and depth
|
||||
for (i = 0; i < len/4; i++) {
|
||||
dc_sample_value_t sample = {0};
|
||||
unsigned int temp = data[0]+256*data[1];
|
||||
unsigned int pressure = data[2]+256*data[3];
|
||||
|
||||
data += 4;
|
||||
sample.time = (i+1)*deepblu->sample_interval;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
|
||||
sample.depth = pressure_to_depth(pressure);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
|
||||
sample.temperature = temp / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
@ -1,516 +0,0 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2021 Ryan Gardner, 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "deepsix_excursion.h"
|
||||
#include "context-private.h"
|
||||
#include "device-private.h"
|
||||
#include "platform.h"
|
||||
#include "checksum.h"
|
||||
#include "array.h"
|
||||
|
||||
#define MAXPACKET 255
|
||||
|
||||
#define HEADERSIZE_MIN 128
|
||||
#define HEADERSIZE_V0 156
|
||||
|
||||
#define NSTEPS 1000
|
||||
#define STEP(i,n) (NSTEPS * (i) / (n))
|
||||
|
||||
#define FP_SIZE 6
|
||||
#define FP_OFFSET 12
|
||||
|
||||
#define DIR_WRITE 0x00
|
||||
#define DIR_READ 0x01
|
||||
|
||||
#define GRP_INFO 0xA0
|
||||
#define CMD_INFO_HARDWARE 0x01
|
||||
#define CMD_INFO_SOFTWARE 0x02
|
||||
#define CMD_INFO_SERIAL 0x03
|
||||
#define CMD_INFO_LASTDIVE 0x04
|
||||
|
||||
#define GRP_SETTINGS 0xB0
|
||||
#define CMD_SETTINGS_DATE 0x01
|
||||
#define CMD_SETTINGS_TIME 0x03
|
||||
#define CMD_SETTINGS_STORE 0x27
|
||||
#define CMD_SETTINGS_LOAD 0x28
|
||||
|
||||
#define GRP_DIVE 0xC0
|
||||
#define CMD_DIVE_HEADER 0x02
|
||||
#define CMD_DIVE_PROFILE 0x03
|
||||
#define CMD_DIVE_COUNT 0x05
|
||||
#define CMD_DIVE_INDEX_LAST 0x06
|
||||
#define CMD_DIVE_INDEX_FIRST 0x07
|
||||
#define CMD_DIVE_INDEX_PREVIOUS 0x08
|
||||
#define CMD_DIVE_INDEX_NEXT 0x09
|
||||
|
||||
typedef struct deepsix_excursion_device_t {
|
||||
dc_device_t base;
|
||||
dc_iostream_t *iostream;
|
||||
unsigned char fingerprint[FP_SIZE];
|
||||
} deepsix_excursion_device_t;
|
||||
|
||||
static dc_status_t deepsix_excursion_device_set_fingerprint (dc_device_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t deepsix_excursion_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
||||
static dc_status_t deepsix_excursion_device_timesync(dc_device_t *abstract, const dc_datetime_t *datetime);
|
||||
|
||||
static const dc_device_vtable_t deepsix_excursion_device_vtable = {
|
||||
sizeof(deepsix_excursion_device_t),
|
||||
DC_FAMILY_DEEPSIX_EXCURSION,
|
||||
deepsix_excursion_device_set_fingerprint, /* set_fingerprint */
|
||||
NULL, /* read */
|
||||
NULL, /* write */
|
||||
NULL, /* dump */
|
||||
deepsix_excursion_device_foreach, /* foreach */
|
||||
deepsix_excursion_device_timesync, /* timesync */
|
||||
NULL, /* close */
|
||||
};
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_send (deepsix_excursion_device_t *device, unsigned char grp, unsigned char cmd, unsigned char dir, const unsigned char data[], unsigned int size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
unsigned char packet[4 + MAXPACKET + 1];
|
||||
|
||||
if (device_is_cancelled (abstract))
|
||||
return DC_STATUS_CANCELLED;
|
||||
|
||||
if (size > MAXPACKET)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Setup the data packet
|
||||
packet[0] = grp;
|
||||
packet[1] = cmd;
|
||||
packet[2] = dir;
|
||||
packet[3] = size;
|
||||
if (size) {
|
||||
memcpy(packet + 4, data, size);
|
||||
}
|
||||
packet[size + 4] = checksum_add_uint8 (packet, size + 4, 0) ^ 0xFF;
|
||||
|
||||
// Send the data packet.
|
||||
status = dc_iostream_write (device->iostream, packet, 4 + size + 1, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_recv (deepsix_excursion_device_t *device, unsigned char grp, unsigned char cmd, unsigned char dir, unsigned char data[], unsigned int size, unsigned int *actual)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
unsigned char packet[4 + MAXPACKET + 1];
|
||||
size_t transferred = 0;
|
||||
|
||||
// Read the packet header, payload and checksum.
|
||||
status = dc_iostream_read (device->iostream, packet, sizeof(packet), &transferred);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the packet.");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (transferred < 4) {
|
||||
ERROR (abstract->context, "Packet header too short ("DC_PRINTF_SIZE").", transferred);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Verify the packet header.
|
||||
if (packet[0] != grp || packet[1] != cmd || packet[2] != dir) {
|
||||
ERROR (device->base.context, "Unexpected packet header.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
unsigned int len = packet[3];
|
||||
if (len > MAXPACKET) {
|
||||
ERROR (abstract->context, "Packet header length too large (%u).", len);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (transferred < 4 + len + 1) {
|
||||
ERROR (abstract->context, "Packet data too short ("DC_PRINTF_SIZE").", transferred);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Verify the checksum.
|
||||
unsigned char csum = checksum_add_uint8 (packet, len + 4, 0) ^ 0xFF;
|
||||
if (packet[len + 4] != csum) {
|
||||
ERROR (abstract->context, "Unexpected packet checksum (%02x)", csum);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (len > size) {
|
||||
ERROR (abstract->context, "Unexpected packet length (%u).", len);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
memcpy(data, packet + 4, len);
|
||||
}
|
||||
|
||||
if (actual)
|
||||
*actual = len;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_transfer (deepsix_excursion_device_t *device, unsigned char grp, unsigned char cmd, unsigned char dir, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int *actual)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
|
||||
status = deepsix_excursion_send (device, grp, cmd, dir, command, csize);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = deepsix_excursion_recv (device, grp + 1, cmd, dir, answer, asize, actual);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
deepsix_excursion_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
deepsix_excursion_device_t *device = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
device = (deepsix_excursion_device_t *) dc_device_allocate (context, &deepsix_excursion_device_vtable);
|
||||
if (device == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
device->iostream = iostream;
|
||||
memset(device->fingerprint, 0, sizeof(device->fingerprint));
|
||||
|
||||
// Set the serial communication protocol (115200 8N1).
|
||||
status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the terminal attributes.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Set the timeout for receiving data (3000ms).
|
||||
status = dc_iostream_set_timeout (device->iostream, 3000);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the timeout.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Make sure everything is in a sane state.
|
||||
dc_iostream_sleep (device->iostream, 300);
|
||||
dc_iostream_purge (device->iostream, DC_DIRECTION_ALL);
|
||||
|
||||
*out = (dc_device_t *) device;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free:
|
||||
dc_device_deallocate ((dc_device_t *) device);
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_device_set_fingerprint (dc_device_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
deepsix_excursion_device_t *device = (deepsix_excursion_device_t *)abstract;
|
||||
|
||||
if (size && size != sizeof (device->fingerprint))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (size)
|
||||
memcpy (device->fingerprint, data, sizeof (device->fingerprint));
|
||||
else
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
deepsix_excursion_device_t *device = (deepsix_excursion_device_t *) abstract;
|
||||
|
||||
// Enable progress notifications.
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
// Load the settings into memory.
|
||||
status = deepsix_excursion_transfer (device, GRP_SETTINGS, CMD_SETTINGS_LOAD, DIR_WRITE, NULL, 0, NULL, 0, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to load the settings.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Read the hardware version.
|
||||
unsigned char rsp_hardware[6] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_INFO, CMD_INFO_HARDWARE, DIR_READ, NULL, 0, rsp_hardware, sizeof(rsp_hardware), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the hardware version.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Read the software version.
|
||||
unsigned char rsp_software[6] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_INFO, CMD_INFO_SOFTWARE, DIR_READ, NULL, 0, rsp_software, sizeof(rsp_software), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the software version.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Read the serial number
|
||||
unsigned char rsp_serial[12] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_INFO, CMD_INFO_SERIAL, DIR_READ, NULL, 0, rsp_serial, sizeof(rsp_serial), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the serial number.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = 0;
|
||||
devinfo.firmware = array_uint16_be (rsp_software + 4);
|
||||
devinfo.serial = array_convert_str2num (rsp_serial + 3, sizeof(rsp_serial) - 3);
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
// Firmware version 6+ uses the new commands.
|
||||
unsigned int fw6 = memcmp(rsp_software, "D01", 3) == 0 && rsp_software[4] >= '6';
|
||||
|
||||
unsigned int ndives = 0, last = 0;
|
||||
if (fw6) {
|
||||
// Read the number of dives.
|
||||
unsigned char rsp_ndives[2] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_DIVE, CMD_DIVE_COUNT, DIR_READ, NULL, 0, rsp_ndives, sizeof(rsp_ndives), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the number of dives");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Read the index of the last dive.
|
||||
unsigned char rsp_last[4] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_DIVE, CMD_DIVE_INDEX_LAST, DIR_READ, NULL, 0, rsp_last, sizeof(rsp_last), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the last dive index.");
|
||||
return status;
|
||||
}
|
||||
|
||||
ndives = array_uint16_le (rsp_ndives);
|
||||
last = array_uint16_le (rsp_last);
|
||||
} else {
|
||||
// Read the index of the last dive.
|
||||
const unsigned char cmd_last[2] = {0};
|
||||
unsigned char rsp_last[2] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_INFO, CMD_INFO_LASTDIVE, DIR_READ, cmd_last, sizeof(cmd_last), rsp_last, sizeof(rsp_last), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the last dive index.");
|
||||
return status;
|
||||
}
|
||||
|
||||
ndives = last = array_uint16_le (rsp_last);
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current = 1 * NSTEPS;
|
||||
progress.maximum = (ndives + 1) * NSTEPS;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
dc_buffer_t *buffer = dc_buffer_new(0);
|
||||
if (buffer == NULL) {
|
||||
ERROR (abstract->context, "Insufficient buffer space available.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
unsigned int number = last;
|
||||
for (unsigned int i = 0; i < ndives; ++i) {
|
||||
if (fw6) {
|
||||
if (i > 0) {
|
||||
const unsigned char cmd_previous[] = {
|
||||
(number ) & 0xFF,
|
||||
(number >> 8) & 0xFF,
|
||||
(number >> 16) & 0xFF,
|
||||
(number >> 24) & 0xFF};
|
||||
unsigned char rsp_previous[4] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_DIVE, CMD_DIVE_INDEX_PREVIOUS, DIR_READ,
|
||||
cmd_previous, sizeof(cmd_previous), rsp_previous, sizeof(rsp_previous), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the previous dive index");
|
||||
return status;
|
||||
}
|
||||
number = array_uint32_le (rsp_previous);
|
||||
}
|
||||
} else {
|
||||
number = ndives - i;
|
||||
}
|
||||
|
||||
unsigned int headersize = 0;
|
||||
const unsigned char cmd_header[] = {
|
||||
(number ) & 0xFF,
|
||||
(number >> 8) & 0xFF};
|
||||
unsigned char rsp_header[MAXPACKET] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_DIVE, CMD_DIVE_HEADER, DIR_READ,
|
||||
cmd_header, sizeof(cmd_header), rsp_header, sizeof(rsp_header), &headersize);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the dive header.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
if (headersize < HEADERSIZE_MIN || headersize != (fw6 ? rsp_header[2] : HEADERSIZE_V0)) {
|
||||
ERROR (abstract->context, "Unexpected size of the dive header (%u).", headersize);
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
if (memcmp(rsp_header + FP_OFFSET, device->fingerprint, sizeof(device->fingerprint)) == 0)
|
||||
break;
|
||||
|
||||
unsigned int length = array_uint32_le (rsp_header + 8);
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current = (i + 1) * NSTEPS + STEP(headersize, headersize + length);
|
||||
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
dc_buffer_clear(buffer);
|
||||
dc_buffer_reserve(buffer, headersize + length);
|
||||
|
||||
if (!dc_buffer_append(buffer, rsp_header, headersize)) {
|
||||
ERROR (abstract->context, "Insufficient buffer space available.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
unsigned offset = 0;
|
||||
while (offset < length) {
|
||||
unsigned int len = 0;
|
||||
const unsigned char cmd_profile[] = {
|
||||
(number ) & 0xFF,
|
||||
(number >> 8) & 0xFF,
|
||||
(offset ) & 0xFF,
|
||||
(offset >> 8) & 0xFF,
|
||||
(offset >> 16) & 0xFF,
|
||||
(offset >> 24) & 0xFF};
|
||||
unsigned char rsp_profile[MAXPACKET] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_DIVE, CMD_DIVE_PROFILE, DIR_READ,
|
||||
cmd_profile, sizeof(cmd_profile), rsp_profile, sizeof(rsp_profile), &len);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the dive profile.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Remove padding from the last packet.
|
||||
unsigned int n = len;
|
||||
if (offset + n > length) {
|
||||
n = length - offset;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current = (i + 1) * NSTEPS + STEP(headersize + offset + n, headersize + length);
|
||||
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
if (!dc_buffer_append(buffer, rsp_profile, n)) {
|
||||
ERROR (abstract->context, "Insufficient buffer space available.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
offset += n;
|
||||
}
|
||||
|
||||
unsigned char *data = dc_buffer_get_data(buffer);
|
||||
unsigned int size = dc_buffer_get_size(buffer);
|
||||
if (callback && !callback (data, size, data + FP_OFFSET, sizeof(device->fingerprint), userdata)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
error_free:
|
||||
dc_buffer_free(buffer);
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
deepsix_excursion_device_t *device = (deepsix_excursion_device_t *) abstract;
|
||||
|
||||
if (datetime->year < 2000) {
|
||||
ERROR (abstract->context, "Invalid date/time value specified.");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
const unsigned char cmd_date[] = {
|
||||
datetime->year - 2000,
|
||||
datetime->month,
|
||||
datetime->day};
|
||||
|
||||
const unsigned char cmd_time[] = {
|
||||
datetime->hour,
|
||||
datetime->minute,
|
||||
datetime->second};
|
||||
|
||||
const unsigned char cmd_store[] = {0x00};
|
||||
|
||||
unsigned char rsp_date[sizeof(cmd_date)] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_SETTINGS, CMD_SETTINGS_DATE, DIR_WRITE, cmd_date, sizeof(cmd_date), rsp_date, sizeof(rsp_date), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to set the date.");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (memcmp(rsp_date, cmd_date, sizeof(cmd_date)) != 0) {
|
||||
ERROR (abstract->context, "Failed to verify the date.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
unsigned char rsp_time[sizeof(cmd_time)] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_SETTINGS, CMD_SETTINGS_TIME, DIR_WRITE, cmd_time, sizeof(cmd_time), rsp_time, sizeof(rsp_time), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to set the time.");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (memcmp(rsp_time, cmd_time, sizeof(cmd_time)) != 0) {
|
||||
ERROR (abstract->context, "Failed to verify the time.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
status = deepsix_excursion_transfer (device, GRP_SETTINGS, CMD_SETTINGS_STORE, DIR_WRITE, cmd_store, sizeof(cmd_store), NULL, 0, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to store the settings.");
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2021 Ryan Gardner, 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 DEEPSIX_EXCURSION_H
|
||||
#define DEEPSIX_EXCURSION_H
|
||||
|
||||
#include <libdivecomputer/context.h>
|
||||
#include <libdivecomputer/iostream.h>
|
||||
#include <libdivecomputer/device.h>
|
||||
#include <libdivecomputer/parser.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
dc_status_t
|
||||
deepsix_excursion_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
deepsix_excursion_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* DEEPSIX_EXCURSION_H */
|
||||
@ -1,768 +0,0 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2021 Ryan Gardner, 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 <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libdivecomputer/units.h>
|
||||
|
||||
#include "deepsix_excursion.h"
|
||||
#include "context-private.h"
|
||||
#include "parser-private.h"
|
||||
#include "array.h"
|
||||
|
||||
#define HEADERSIZE_MIN 128
|
||||
|
||||
#define MAX_SAMPLES 7
|
||||
#define MAX_EVENTS 7
|
||||
#define MAX_GASMIXES 20
|
||||
|
||||
#define ALARM 0x0001
|
||||
#define TEMPERATURE 0x0002
|
||||
#define DECO 0x0003
|
||||
#define CEILING 0x0004
|
||||
#define CNS 0x0005
|
||||
|
||||
#define SAMPLE_TEMPERATURE 0
|
||||
#define SAMPLE_DECO_NDL 1
|
||||
#define SAMPLE_CNS 2
|
||||
|
||||
#define EVENT_CHANGE_GAS 7
|
||||
#define EVENT_ALARMS 8
|
||||
#define EVENT_CHANGE_SETPOINT 9
|
||||
#define EVENT_SAMPLES_MISSED 10
|
||||
#define EVENT_RESERVED 15
|
||||
|
||||
#define ALARM_ASCENTRATE 0
|
||||
#define ALARM_CEILING 1
|
||||
#define ALARM_PO2 2
|
||||
#define ALARM_MAXDEPTH 3
|
||||
#define ALARM_DIVETIME 4
|
||||
#define ALARM_CNS 5
|
||||
|
||||
#define DECOSTOP 0x02
|
||||
#define SAFETYSTOP 0x04
|
||||
|
||||
#define DENSITY 1024
|
||||
|
||||
#define UNDEFINED 0xFFFFFFFF
|
||||
|
||||
#define FWVERSION(major,minor) ( \
|
||||
((((major) + '0') & 0xFF) << 8) | \
|
||||
((minor) & 0xFF))
|
||||
|
||||
typedef struct deepsix_excursion_layout_t {
|
||||
unsigned int headersize;
|
||||
unsigned int version;
|
||||
unsigned int divemode;
|
||||
unsigned int samplerate;
|
||||
unsigned int salinity;
|
||||
unsigned int datetime;
|
||||
unsigned int divetime;
|
||||
unsigned int maxdepth;
|
||||
unsigned int temperature_min;
|
||||
unsigned int avgdepth;
|
||||
unsigned int firmware;
|
||||
unsigned int temperature_surf;
|
||||
unsigned int atmospheric;
|
||||
unsigned int gf;
|
||||
} deepsix_excursion_layout_t;
|
||||
|
||||
typedef struct deepsix_excursion_gasmix_t {
|
||||
unsigned int id;
|
||||
unsigned int oxygen;
|
||||
unsigned int helium;
|
||||
} deepsix_excursion_gasmix_t;
|
||||
|
||||
typedef struct deepsix_excursion_sample_info_t {
|
||||
unsigned int type;
|
||||
unsigned int divisor;
|
||||
unsigned int size;
|
||||
} deepsix_excursion_sample_info_t;
|
||||
|
||||
typedef struct deepsix_excursion_event_info_t {
|
||||
unsigned int type;
|
||||
unsigned int size;
|
||||
} deepsix_excursion_event_info_t;
|
||||
|
||||
typedef struct deepsix_excursion_parser_t {
|
||||
dc_parser_t base;
|
||||
unsigned int cached;
|
||||
unsigned int ngasmixes;
|
||||
deepsix_excursion_gasmix_t gasmix[MAX_GASMIXES];
|
||||
} deepsix_excursion_parser_t;
|
||||
|
||||
static dc_status_t deepsix_excursion_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t deepsix_excursion_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t deepsix_excursion_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
static dc_status_t deepsix_excursion_parser_samples_foreach_v0 (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
static dc_status_t deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
|
||||
static const dc_parser_vtable_t deepsix_parser_vtable = {
|
||||
sizeof(deepsix_excursion_parser_t),
|
||||
DC_FAMILY_DEEPSIX_EXCURSION,
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
deepsix_excursion_parser_get_datetime, /* datetime */
|
||||
deepsix_excursion_parser_get_field, /* fields */
|
||||
deepsix_excursion_parser_samples_foreach, /* samples_foreach */
|
||||
NULL /* destroy */
|
||||
};
|
||||
|
||||
static const deepsix_excursion_layout_t deepsix_excursion_layout_v0 = {
|
||||
156,/* headersize */
|
||||
UNDEFINED, /* version */
|
||||
4, /* divemode */
|
||||
24, /* samplerate */
|
||||
UNDEFINED, /* salinity */
|
||||
12, /* datetime */
|
||||
20, /* divetime */
|
||||
28, /* maxdepth */
|
||||
32, /* temperature_min */
|
||||
UNDEFINED, /* avgdepth */
|
||||
48, /* firmware */
|
||||
UNDEFINED, /* temperature_surf */
|
||||
56, /* atmospheric */
|
||||
UNDEFINED, /* gf */
|
||||
};
|
||||
|
||||
static const deepsix_excursion_layout_t deepsix_excursion_layout_v1 = {
|
||||
129,/* headersize */
|
||||
3, /* version */
|
||||
4, /* divemode */
|
||||
5, /* samplerate */
|
||||
7, /* salinity */
|
||||
12, /* datetime */
|
||||
19, /* divetime */
|
||||
29, /* maxdepth */
|
||||
31, /* temperature_min */
|
||||
33, /* avgdepth */
|
||||
35, /* firmware */
|
||||
43, /* temperature_surf */
|
||||
45, /* atmospheric */
|
||||
127, /* gf */
|
||||
};
|
||||
|
||||
static double
|
||||
pressure_to_depth(unsigned int depth, unsigned int atmospheric, unsigned int density)
|
||||
{
|
||||
return ((signed int)(depth - atmospheric)) * (BAR / 1000.0) / (density * GRAVITY);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
deepsix_excursion_find_gasmix(deepsix_excursion_parser_t *parser, unsigned int o2, unsigned int he, unsigned int id)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
while (i < parser->ngasmixes) {
|
||||
if (o2 == parser->gasmix[i].oxygen && he == parser->gasmix[i].helium && id == parser->gasmix[i].id)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
deepsix_excursion_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
deepsix_excursion_parser_t *parser = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (deepsix_excursion_parser_t *) dc_parser_allocate (context, &deepsix_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
parser->cached = 0;
|
||||
parser->ngasmixes = 0;
|
||||
for (unsigned int i = 0; i < MAX_GASMIXES; ++i) {
|
||||
parser->gasmix[i].id = 0;
|
||||
parser->gasmix[i].oxygen = 0;
|
||||
parser->gasmix[i].helium = 0;
|
||||
}
|
||||
|
||||
*out = (dc_parser_t *) parser;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
if (size < HEADERSIZE_MIN)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int version = data[3];
|
||||
const deepsix_excursion_layout_t *layout = version == 0 ?
|
||||
&deepsix_excursion_layout_v0 : &deepsix_excursion_layout_v1;
|
||||
|
||||
if (size < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int firmware = array_uint16_be (data + layout->firmware + 4);
|
||||
|
||||
const unsigned char *p = data + layout->datetime;
|
||||
|
||||
if (datetime) {
|
||||
datetime->year = p[0] + 2000;
|
||||
datetime->month = p[1];
|
||||
datetime->day = p[2];
|
||||
datetime->hour = p[3];
|
||||
datetime->minute = p[4];
|
||||
datetime->second = p[5];
|
||||
|
||||
if (version == 0) {
|
||||
if (firmware >= FWVERSION(5, 'B')) {
|
||||
datetime->timezone = (p[6] - 12) * 3600;
|
||||
} else {
|
||||
datetime->timezone = DC_TIMEZONE_NONE;
|
||||
}
|
||||
} else {
|
||||
datetime->timezone = ((signed char) p[6]) * 900;
|
||||
}
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
|
||||
{
|
||||
deepsix_excursion_parser_t *parser = (deepsix_excursion_parser_t *) abstract;
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
dc_salinity_t *water = (dc_salinity_t *) value;
|
||||
dc_decomodel_t *decomodel = (dc_decomodel_t *) value;
|
||||
|
||||
if (size < HEADERSIZE_MIN)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int version = data[3];
|
||||
const deepsix_excursion_layout_t *layout = version == 0 ?
|
||||
&deepsix_excursion_layout_v0 : &deepsix_excursion_layout_v1;
|
||||
|
||||
if (size < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
if (version != 0 && !parser->cached) {
|
||||
dc_status_t rc = deepsix_excursion_parser_samples_foreach_v1(abstract, NULL, NULL);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
}
|
||||
|
||||
unsigned int atmospheric = array_uint16_le(data + layout->atmospheric);
|
||||
unsigned int density = DENSITY;
|
||||
if (layout->salinity != UNDEFINED) {
|
||||
density = 1000 + data[layout->salinity] * 10;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
switch (type) {
|
||||
case DC_FIELD_DIVETIME:
|
||||
*((unsigned int *) value) = array_uint32_le(data + layout->divetime);
|
||||
break;
|
||||
case DC_FIELD_MAXDEPTH:
|
||||
*((double *) value) = pressure_to_depth(array_uint16_le(data + layout->maxdepth), atmospheric, density);
|
||||
break;
|
||||
case DC_FIELD_AVGDEPTH:
|
||||
if (layout->avgdepth == UNDEFINED)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((double *) value) = pressure_to_depth(array_uint16_le(data + layout->avgdepth), atmospheric, density);
|
||||
break;
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
|
||||
gasmix->helium = parser->gasmix[flags].helium / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
break;
|
||||
case DC_FIELD_TEMPERATURE_MINIMUM:
|
||||
*((double *) value) = (signed int) array_uint16_le(data + layout->temperature_min) / 10.0;
|
||||
break;
|
||||
case DC_FIELD_TEMPERATURE_SURFACE:
|
||||
if (layout->temperature_surf == UNDEFINED)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((double *) value) = (signed int) array_uint16_le(data + layout->temperature_surf) / 10.0;
|
||||
break;
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
*((double *) value) = atmospheric / 1000.0;
|
||||
break;
|
||||
case DC_FIELD_SALINITY:
|
||||
water->type = (density == 1000) ? DC_WATER_FRESH : DC_WATER_SALT;
|
||||
water->density = density;
|
||||
break;
|
||||
case DC_FIELD_DIVEMODE:
|
||||
switch (data[layout->divemode]) {
|
||||
case 0:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_OC;
|
||||
break;
|
||||
case 1:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_GAUGE;
|
||||
break;
|
||||
case 2:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_FREEDIVE;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_DECOMODEL:
|
||||
decomodel->type = DC_DECOMODEL_BUHLMANN;
|
||||
decomodel->conservatism = 0;
|
||||
if (layout->gf != UNDEFINED) {
|
||||
decomodel->params.gf.low = data[layout->gf + 0];
|
||||
decomodel->params.gf.high = data[layout->gf + 1];
|
||||
} else {
|
||||
decomodel->params.gf.low = 0;
|
||||
decomodel->params.gf.high = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_parser_samples_foreach_v0 (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
const deepsix_excursion_layout_t *layout = &deepsix_excursion_layout_v0;
|
||||
|
||||
if (size < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
int firmware4c = memcmp(data + layout->firmware, "D01-4C", 6) == 0;
|
||||
|
||||
unsigned int maxtype = firmware4c ? TEMPERATURE : CNS;
|
||||
|
||||
unsigned int interval = array_uint32_le(data + layout->samplerate);
|
||||
unsigned int atmospheric = array_uint32_le(data + layout->atmospheric);
|
||||
|
||||
unsigned int time = 0;
|
||||
unsigned int offset = layout->headersize;
|
||||
while (offset + 1 < size) {
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
// Get the sample type.
|
||||
unsigned int type = data[offset];
|
||||
if (type < 1 || type > maxtype) {
|
||||
ERROR (abstract->context, "Unknown sample type (%u).", type);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Get the sample length.
|
||||
unsigned int length = 1;
|
||||
if (type == ALARM || type == CEILING) {
|
||||
length = 8;
|
||||
} else if (type == TEMPERATURE || type == DECO || type == CNS) {
|
||||
length = 6;
|
||||
}
|
||||
|
||||
// Verify the length.
|
||||
if (offset + length > size) {
|
||||
WARNING (abstract->context, "Unexpected end of data.");
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned int misc = data[offset + 1];
|
||||
unsigned int depth = array_uint16_le(data + offset + 2);
|
||||
|
||||
if (type == TEMPERATURE) {
|
||||
time += interval;
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback(DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
sample.depth = pressure_to_depth(depth, atmospheric, DENSITY);
|
||||
if (callback) callback(DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
}
|
||||
|
||||
if (type == ALARM) {
|
||||
unsigned int alarm_time = array_uint16_le(data + offset + 4);
|
||||
unsigned int alarm_value = array_uint16_le(data + offset + 6);
|
||||
} else if (type == TEMPERATURE) {
|
||||
unsigned int temperature = array_uint16_le(data + offset + 4);
|
||||
if (firmware4c) {
|
||||
if (temperature > 1300) {
|
||||
length = 8;
|
||||
} else if (temperature >= 10) {
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
} else {
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
} else if (type == DECO) {
|
||||
unsigned int deco = array_uint16_le(data + offset + 4);
|
||||
} else if (type == CEILING) {
|
||||
unsigned int ceiling_depth = array_uint16_le(data + offset + 4);
|
||||
unsigned int ceiling_time = array_uint16_le(data + offset + 6);
|
||||
} else if (type == CNS) {
|
||||
unsigned int cns = array_uint16_le(data + offset + 4);
|
||||
sample.cns = cns / 100.0;
|
||||
if (callback) callback(DC_SAMPLE_CNS, &sample, userdata);
|
||||
}
|
||||
|
||||
offset += length;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
deepsix_excursion_parser_t *parser = (deepsix_excursion_parser_t *) abstract;
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
const deepsix_excursion_layout_t *layout = &deepsix_excursion_layout_v1;
|
||||
|
||||
if (size < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int headersize = data[2];
|
||||
if (headersize < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int samplerate = data[layout->samplerate];
|
||||
unsigned int atmospheric = array_uint16_le(data + layout->atmospheric);
|
||||
unsigned int density = 1000 + data[layout->salinity] * 10;
|
||||
|
||||
unsigned int offset = headersize;
|
||||
if (offset + 1 > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned int nconfig = data[offset];
|
||||
if (nconfig > MAX_SAMPLES) {
|
||||
ERROR(abstract->context, "Too many sample descriptors (%u).", nconfig);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
offset += 1;
|
||||
|
||||
if (offset + 3 * nconfig > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
deepsix_excursion_sample_info_t sample_info[MAX_SAMPLES] = {{0}};
|
||||
for (unsigned int i = 0; i < nconfig; i++) {
|
||||
sample_info[i].type = data[offset + 3 * i + 0];
|
||||
sample_info[i].size = data[offset + 3 * i + 1];
|
||||
sample_info[i].divisor = data[offset + 3 * i + 2];
|
||||
|
||||
if (sample_info[i].divisor) {
|
||||
switch (sample_info[i].type) {
|
||||
case SAMPLE_CNS:
|
||||
case SAMPLE_TEMPERATURE:
|
||||
if (sample_info[i].size != 2) {
|
||||
ERROR(abstract->context, "Unexpected sample size (%u).", sample_info[i].size);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case SAMPLE_DECO_NDL:
|
||||
if (sample_info[i].size != 7) {
|
||||
ERROR(abstract->context, "Unexpected sample size (%u).", sample_info[i].size);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARNING (abstract->context, "Unknown sample descriptor (%u %u %u).",
|
||||
sample_info[i].type, sample_info[i].size, sample_info[i].divisor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
offset += 3 * nconfig;
|
||||
|
||||
if (offset + 1 > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned int nevents = data[offset];
|
||||
if (nevents > MAX_EVENTS) {
|
||||
ERROR(abstract->context, "Too many event descriptors (%u).", nevents);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
offset += 1;
|
||||
|
||||
if (offset + 2 * nevents > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
deepsix_excursion_event_info_t event_info[MAX_EVENTS] = {{0}};
|
||||
for (unsigned int i = 0; i < nevents; i++) {
|
||||
event_info[i].type = data[offset + 2 * i];
|
||||
event_info[i].size = data[offset + 2 * i + 1];
|
||||
|
||||
switch (event_info[i].type) {
|
||||
case EVENT_ALARMS:
|
||||
if (event_info[i].size != 1) {
|
||||
ERROR(abstract->context, "Unexpected event size (%u).", event_info[i].size);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case EVENT_CHANGE_GAS:
|
||||
if (event_info[i].size != 3) {
|
||||
ERROR(abstract->context, "Unexpected event size (%u).", event_info[i].size);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case EVENT_SAMPLES_MISSED:
|
||||
if (event_info[i].size != 6) {
|
||||
ERROR(abstract->context, "Unexpected event size (%u).", event_info[i].size);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARNING (abstract->context, "Unknown event descriptor (%u %u).",
|
||||
event_info[i].type, event_info[i].size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
offset += 2 * nevents;
|
||||
|
||||
unsigned int time = 0;
|
||||
unsigned int nsamples = 0;
|
||||
while (offset + 3 <= size) {
|
||||
dc_sample_value_t sample = {0};
|
||||
nsamples++;
|
||||
|
||||
// Time (seconds).
|
||||
time += samplerate;
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
unsigned int depth = array_uint16_le (data + offset);
|
||||
sample.depth = pressure_to_depth(depth, atmospheric, density);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
offset += 2;
|
||||
|
||||
// event info
|
||||
unsigned int length = data[offset];
|
||||
offset += 1;
|
||||
|
||||
if (offset + length > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
if (length) {
|
||||
if (length < 2) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned int events = array_uint16_le (data + offset);
|
||||
unsigned int event_offset = 2;
|
||||
|
||||
for (unsigned int i = 0; i < nevents; i++) {
|
||||
if ((events & (1 << event_info[i].type)) == 0)
|
||||
continue;
|
||||
|
||||
if (event_offset + event_info[i].size > length) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned int alarms = 0;
|
||||
unsigned int id = 0, o2 = 0, he = 0;
|
||||
unsigned int mix_idx = 0;
|
||||
unsigned int count = 0, timestamp = 0;
|
||||
switch (event_info[i].type) {
|
||||
case EVENT_ALARMS:
|
||||
alarms = data[offset + event_offset];
|
||||
for (unsigned int v = alarms, j = 0; v; v >>= 1, ++j) {
|
||||
if ((v & 1) == 0)
|
||||
continue;
|
||||
|
||||
sample.event.type = SAMPLE_EVENT_NONE;
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = 0;
|
||||
switch (j) {
|
||||
case ALARM_ASCENTRATE:
|
||||
sample.event.type = SAMPLE_EVENT_ASCENT;
|
||||
break;
|
||||
case ALARM_CEILING:
|
||||
sample.event.type = SAMPLE_EVENT_CEILING;
|
||||
break;
|
||||
case ALARM_PO2:
|
||||
sample.event.type = SAMPLE_EVENT_PO2;
|
||||
break;
|
||||
case ALARM_MAXDEPTH:
|
||||
sample.event.type = SAMPLE_EVENT_MAXDEPTH;
|
||||
break;
|
||||
case ALARM_DIVETIME:
|
||||
sample.event.type = SAMPLE_EVENT_DIVETIME;
|
||||
break;
|
||||
case ALARM_CNS:
|
||||
break;
|
||||
default:
|
||||
WARNING (abstract->context, "Unknown event (%u).", j);
|
||||
break;
|
||||
}
|
||||
if (sample.event.type != SAMPLE_EVENT_NONE) {
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EVENT_CHANGE_GAS:
|
||||
id = data[offset + event_offset];
|
||||
o2 = data[offset + event_offset + 1];
|
||||
he = data[offset + event_offset + 2];
|
||||
|
||||
mix_idx = deepsix_excursion_find_gasmix(parser, o2, he, id);
|
||||
if (mix_idx >= parser->ngasmixes) {
|
||||
if (mix_idx >= MAX_GASMIXES) {
|
||||
ERROR (abstract->context, "Maximum number of gas mixes reached.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
parser->gasmix[mix_idx].oxygen = o2;
|
||||
parser->gasmix[mix_idx].helium = he;
|
||||
parser->gasmix[mix_idx].id = id;
|
||||
parser->ngasmixes = mix_idx + 1;
|
||||
}
|
||||
|
||||
sample.gasmix = mix_idx;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
break;
|
||||
case EVENT_SAMPLES_MISSED:
|
||||
count = array_uint16_le(data + offset + event_offset);
|
||||
timestamp = array_uint32_le(data + offset + event_offset + 2);
|
||||
if (timestamp < time) {
|
||||
ERROR (abstract->context, "Timestamp moved backwards (%u %u).", timestamp, time);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
nsamples += count;
|
||||
time = timestamp;
|
||||
break;
|
||||
default:
|
||||
WARNING (abstract->context, "Unknown event (%u %u).",
|
||||
event_info[i].type, event_info[i].size);
|
||||
break;
|
||||
}
|
||||
event_offset += event_info[i].size;
|
||||
}
|
||||
|
||||
// Skip remaining sample bytes (if any).
|
||||
if (event_offset < length) {
|
||||
WARNING (abstract->context, "Remaining %u bytes skipped.", length - event_offset);
|
||||
}
|
||||
offset += length;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < nconfig; ++i) {
|
||||
if (sample_info[i].divisor && (nsamples % sample_info[i].divisor) == 0) {
|
||||
if (offset + sample_info[i].size > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned int value = 0;
|
||||
unsigned int deco_flags = 0, deco_ndl_tts = 0;
|
||||
unsigned int deco_depth = 0, deco_time = 0;
|
||||
switch (sample_info[i].type) {
|
||||
case SAMPLE_TEMPERATURE:
|
||||
value = array_uint16_le(data + offset);
|
||||
sample.temperature = value / 10.0;
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
break;
|
||||
case SAMPLE_CNS:
|
||||
value = array_uint16_le(data + offset);
|
||||
sample.cns = value / 10000.0;
|
||||
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata);
|
||||
break;
|
||||
case SAMPLE_DECO_NDL:
|
||||
deco_flags = data[offset];
|
||||
deco_ndl_tts = array_uint16_le(data + offset + 1);
|
||||
deco_depth = array_uint16_le(data + offset + 3);
|
||||
deco_time = array_uint16_le(data + offset + 5);
|
||||
if (deco_flags & DECOSTOP) {
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = pressure_to_depth(deco_depth, atmospheric, density);
|
||||
sample.deco.time = deco_time;
|
||||
} else if (deco_flags & SAFETYSTOP) {
|
||||
sample.deco.type = DC_DECO_SAFETYSTOP;
|
||||
sample.deco.depth = pressure_to_depth(deco_depth, atmospheric, density);
|
||||
sample.deco.time = deco_time;
|
||||
} else {
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.depth = 0;
|
||||
sample.deco.time = deco_ndl_tts;
|
||||
}
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
offset += sample_info[i].size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parser->cached = 1;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
if (size < HEADERSIZE_MIN)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int version = data[3];
|
||||
|
||||
if (version == 0) {
|
||||
return deepsix_excursion_parser_samples_foreach_v0(abstract, callback, userdata);
|
||||
} else {
|
||||
return deepsix_excursion_parser_samples_foreach_v1(abstract, callback, userdata);
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2022 Jef Driesen
|
||||
* Copyright (C) 2017 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,17 +19,33 @@
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef OCEANS_S1_COMMON_H
|
||||
#define OCEANS_S1_COMMON_H
|
||||
#ifndef DC_DESCRIPTOR_PRIVATE_H
|
||||
#define DC_DESCRIPTOR_PRIVATE_H
|
||||
|
||||
#include <libdivecomputer/descriptor.h>
|
||||
|
||||
// Oh joy. Windows is some truly horrendously broken crap
|
||||
#undef interface
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct dc_usb_desc_t {
|
||||
unsigned short vid;
|
||||
unsigned short pid;
|
||||
} dc_usb_desc_t;
|
||||
|
||||
typedef struct dc_usb_params_t {
|
||||
unsigned int interface;
|
||||
unsigned char endpoint_in;
|
||||
unsigned char endpoint_out;
|
||||
} dc_usb_params_t;
|
||||
|
||||
int
|
||||
oceans_s1_getline (char **line, size_t *linelen, const unsigned char **data, size_t *size);
|
||||
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata, void *params);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* OCEANS_S1_COMMON_H */
|
||||
#endif /* DC_DESCRIPTOR_PRIVATE_H */
|
||||
292
src/descriptor.c
292
src/descriptor.c
@ -23,10 +23,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libdivecomputer/descriptor.h>
|
||||
#include <libdivecomputer/usbhid.h>
|
||||
#include <libdivecomputer/usb.h>
|
||||
|
||||
#include "descriptor-private.h"
|
||||
#include "iterator-private.h"
|
||||
#include "platform.h"
|
||||
|
||||
@ -39,29 +36,37 @@
|
||||
values, \
|
||||
C_ARRAY_SIZE(values) - isnullterminated, \
|
||||
C_ARRAY_ITEMSIZE(values), \
|
||||
match)
|
||||
match, \
|
||||
NULL, NULL, 0)
|
||||
|
||||
#define DC_FILTER_INTERNAL_WITH_PARAMS(key, values, isnullterminated, match, params_dst, params_src) \
|
||||
dc_filter_internal( \
|
||||
key, \
|
||||
values, \
|
||||
C_ARRAY_SIZE(values) - isnullterminated, \
|
||||
C_ARRAY_ITEMSIZE(values), \
|
||||
match, \
|
||||
params_dst, params_src, sizeof *(params_src))
|
||||
|
||||
typedef int (*dc_match_t)(const void *, const void *);
|
||||
|
||||
typedef int (*dc_filter_t) (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
typedef int (*dc_filter_t) (dc_transport_t transport, const void *userdata, void *params);
|
||||
|
||||
static int dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_suunto (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_shearwater (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_hw (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_tecdiving (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_mares (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_divesystem (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_mclean (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_atomic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_deepsix (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_deepblu (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_oceans (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_divesoft (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_suunto (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_shearwater (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_hw (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_mares (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_divesystem (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_mclean (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_atomic (dc_transport_t transport, const void *userdata, void *params);
|
||||
|
||||
// Not merged upstream yet
|
||||
static int dc_filter_garmin (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_garmin (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_deepblu (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_oceans(dc_transport_t transport, const void *userdata, void *params);
|
||||
|
||||
static dc_status_t dc_descriptor_iterator_next (dc_iterator_t *iterator, void *item);
|
||||
|
||||
@ -125,13 +130,11 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Suunto", "DX", DC_FAMILY_SUUNTO_D9, 0x1C, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Suunto", "Vyper Novo", DC_FAMILY_SUUNTO_D9, 0x1D, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Suunto", "Zoop Novo", DC_FAMILY_SUUNTO_D9, 0x1E, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Suunto", "Zoop Novo", DC_FAMILY_SUUNTO_D9, 0x1F, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Suunto", "D4f", DC_FAMILY_SUUNTO_D9, 0x20, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Suunto EON Steel */
|
||||
{"Suunto", "EON Steel", DC_FAMILY_SUUNTO_EONSTEEL, 0, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_suunto},
|
||||
{"Suunto", "EON Core", DC_FAMILY_SUUNTO_EONSTEEL, 1, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_suunto},
|
||||
{"Suunto", "D5", DC_FAMILY_SUUNTO_EONSTEEL, 2, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_suunto},
|
||||
{"Suunto", "EON Steel Black", DC_FAMILY_SUUNTO_EONSTEEL, 3, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_suunto},
|
||||
{"Suunto", "EON Steel", DC_FAMILY_SUUNTO_EONSTEEL, 0, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_suunto},
|
||||
{"Suunto", "EON Core", DC_FAMILY_SUUNTO_EONSTEEL, 1, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_suunto},
|
||||
{"Suunto", "D5", DC_FAMILY_SUUNTO_EONSTEEL, 2, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_suunto},
|
||||
/* Uwatec Aladin */
|
||||
{"Uwatec", "Aladin Air Twin", DC_FAMILY_UWATEC_ALADIN, 0x1C, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Uwatec", "Aladin Sport Plus", DC_FAMILY_UWATEC_ALADIN, 0x3E, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -169,14 +172,9 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Scubapro", "Chromis", DC_FAMILY_UWATEC_SMART, 0x24, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Scubapro", "Aladin A1", DC_FAMILY_UWATEC_SMART, 0x25, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "Mantis 2", DC_FAMILY_UWATEC_SMART, 0x26, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Scubapro", "Aladin A2", DC_FAMILY_UWATEC_SMART, 0x28, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G2 TEK", DC_FAMILY_UWATEC_SMART, 0x31, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G2", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G2 Console", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G3", DC_FAMILY_UWATEC_SMART, 0x34, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G2 HUD", DC_FAMILY_UWATEC_SMART, 0x42, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "Luna 2.0 AI", DC_FAMILY_UWATEC_SMART, 0x50, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "Luna 2.0", DC_FAMILY_UWATEC_SMART, 0x51, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
/* Reefnet */
|
||||
{"Reefnet", "Sensus", DC_FAMILY_REEFNET_SENSUS, 1, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Reefnet", "Sensus Pro", DC_FAMILY_REEFNET_SENSUSPRO, 2, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -255,11 +253,10 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Sherwood", "Vision", DC_FAMILY_OCEANIC_ATOM2, 0x4556, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Oceanic", "VTX", DC_FAMILY_OCEANIC_ATOM2, 0x4557, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Aqualung", "i300", DC_FAMILY_OCEANIC_ATOM2, 0x4559, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Aqualung", "i750TC", DC_FAMILY_OCEANIC_ATOM2, 0x455A, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i750TC", DC_FAMILY_OCEANIC_ATOM2, 0x455A, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, NULL},
|
||||
{"Aqualung", "i450T", DC_FAMILY_OCEANIC_ATOM2, 0x4641, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Aqualung", "i550", DC_FAMILY_OCEANIC_ATOM2, 0x4642, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Aqualung", "i200", DC_FAMILY_OCEANIC_ATOM2, 0x4646, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Sherwood", "Sage", DC_FAMILY_OCEANIC_ATOM2, 0x4647, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i300C", DC_FAMILY_OCEANIC_ATOM2, 0x4648, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i200C", DC_FAMILY_OCEANIC_ATOM2, 0x4649, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i100", DC_FAMILY_OCEANIC_ATOM2, 0x464E, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -269,15 +266,7 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Oceanic", "Veo 4.0", DC_FAMILY_OCEANIC_ATOM2, 0x4654, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Sherwood", "Wisdom 4", DC_FAMILY_OCEANIC_ATOM2, 0x4655, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Oceanic", "Pro Plus 4", DC_FAMILY_OCEANIC_ATOM2, 0x4656, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Sherwood", "Amphos 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4657, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Sherwood", "Amphos Air 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4658, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Sherwood", "Beacon", DC_FAMILY_OCEANIC_ATOM2, 0x4742, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i470TC", DC_FAMILY_OCEANIC_ATOM2, 0x4743, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i200Cv2", DC_FAMILY_OCEANIC_ATOM2, 0x4749, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Oceanic", "Geo Air", DC_FAMILY_OCEANIC_ATOM2, 0x474B, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
/* Pelagic I330R */
|
||||
{"Apeks", "DSX", DC_FAMILY_PELAGIC_I330R, 0x4741, DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i330R", DC_FAMILY_PELAGIC_I330R, 0x4744, DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
/* Mares Nemo */
|
||||
{"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -302,14 +291,12 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Mares", "Icon HD", DC_FAMILY_MARES_ICONHD , 0x14, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Mares", "Icon HD Net Ready", DC_FAMILY_MARES_ICONHD , 0x15, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Mares", "Puck Pro", DC_FAMILY_MARES_ICONHD , 0x18, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
||||
{"Mares", "Puck Pro +", DC_FAMILY_MARES_ICONHD , 0x18, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
||||
{"Mares", "Nemo Wide 2", DC_FAMILY_MARES_ICONHD , 0x19, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Mares", "Genius", DC_FAMILY_MARES_ICONHD , 0x1C, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
||||
{"Mares", "Puck 2", DC_FAMILY_MARES_ICONHD , 0x1F, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Mares", "Quad Air", DC_FAMILY_MARES_ICONHD , 0x23, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
||||
{"Mares", "Smart Air", DC_FAMILY_MARES_ICONHD , 0x24, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
||||
{"Mares", "Quad", DC_FAMILY_MARES_ICONHD , 0x29, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
||||
{"Mares", "Horizon", DC_FAMILY_MARES_ICONHD , 0x2C, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Heinrichs Weikamp */
|
||||
{"Heinrichs Weikamp", "OSTC", DC_FAMILY_HW_OSTC, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Heinrichs Weikamp", "OSTC Mk2", DC_FAMILY_HW_OSTC, 1, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -337,11 +324,8 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Cressi", "Newton", DC_FAMILY_CRESSI_LEONARDO, 5, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Cressi", "Drake", DC_FAMILY_CRESSI_LEONARDO, 6, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Cressi Goa */
|
||||
{"Cressi", "Cartesio", DC_FAMILY_CRESSI_GOA, 1, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Cressi", "Goa", DC_FAMILY_CRESSI_GOA, 2, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Cressi", "Donatello", DC_FAMILY_CRESSI_GOA, 4, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Cressi", "Michelangelo", DC_FAMILY_CRESSI_GOA, 5, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Cressi", "Neon", DC_FAMILY_CRESSI_GOA, 9, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Cressi", "Cartesio", DC_FAMILY_CRESSI_GOA, 1, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, NULL},
|
||||
{"Cressi", "Goa", DC_FAMILY_CRESSI_GOA, 2, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, NULL},
|
||||
/* Zeagle N2iTiON3 */
|
||||
{"Zeagle", "N2iTiON3", DC_FAMILY_ZEAGLE_N2ITION3, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Apeks", "Quantum X", DC_FAMILY_ZEAGLE_N2ITION3, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -361,9 +345,6 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Shearwater", "Nerd 2", DC_FAMILY_SHEARWATER_PETREL, 7, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Teric", DC_FAMILY_SHEARWATER_PETREL, 8, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Peregrine", DC_FAMILY_SHEARWATER_PETREL, 9, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Petrel 3", DC_FAMILY_SHEARWATER_PETREL, 10, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Perdix 2", DC_FAMILY_SHEARWATER_PETREL, 11, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Tern", DC_FAMILY_SHEARWATER_PETREL, 12, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
/* Dive Rite NiTek Q */
|
||||
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Citizen Hyper Aqualand */
|
||||
@ -405,37 +386,6 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Ratio", "iDive Color Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x54, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iDive Color Tech+",DC_FAMILY_DIVESYSTEM_IDIVE, 0x55, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iDive Color Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x56, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iX3M 2021 GPS Fancy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x60, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2021 GPS Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x61, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2021 GPS Pro ", DC_FAMILY_DIVESYSTEM_IDIVE, 0x62, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2021 GPS Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x63, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2021 GPS Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x64, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2021 GPS Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x65, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2021 Pro Fancy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x70, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iX3M 2021 Pro Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x71, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iX3M 2021 Pro Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x72, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iX3M 2021 Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x73, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iX3M 2021 Pro Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x74, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iX3M 2021 Pro Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x75, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iDive 2 Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x80, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Fancy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x81, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x82, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x83, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x84, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Tech", DC_FAMILY_DIVESYSTEM_IDIVE, 0x85, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x86, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Gauge", DC_FAMILY_DIVESYSTEM_IDIVE, 0x90, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x91, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x92, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x93, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Tech", DC_FAMILY_DIVESYSTEM_IDIVE, 0x94, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x95, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "ATOM", DC_FAMILY_DIVESYSTEM_IDIVE, 0x96, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Gauge", DC_FAMILY_DIVESYSTEM_IDIVE, 0x100, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x101, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x102, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x103, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x104, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Seac", "Jack", DC_FAMILY_DIVESYSTEM_IDIVE, 0x1000, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Seac", "Guru", DC_FAMILY_DIVESYSTEM_IDIVE, 0x1002, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Cochran Commander */
|
||||
@ -454,32 +404,15 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Liquivision", "Xeo", DC_FAMILY_LIQUIVISION_LYNX, 1, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Liquivision", "Lynx", DC_FAMILY_LIQUIVISION_LYNX, 2, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Liquivision", "Kaon", DC_FAMILY_LIQUIVISION_LYNX, 3, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Sporasub */
|
||||
{"Sporasub", "SP2", DC_FAMILY_SPORASUB_SP2, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Deep Six Excursion */
|
||||
{"Deep Six", "Excursion", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||
{"Crest", "CR-4", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||
{"Genesis", "Centauri", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||
{"Scorpena", "Alpha", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||
/* Seac Screen */
|
||||
{"Seac", "Screen", DC_FAMILY_SEAC_SCREEN, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Seac", "Action", DC_FAMILY_SEAC_SCREEN, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Deepblu Cosmiq */
|
||||
{"Deepblu", "Cosmiq+", DC_FAMILY_DEEPBLU_COSMIQ, 0, DC_TRANSPORT_BLE, dc_filter_deepblu},
|
||||
/* Oceans S1 */
|
||||
{"Oceans", "S1", DC_FAMILY_OCEANS_S1, 0, DC_TRANSPORT_BLE, dc_filter_oceans},
|
||||
/* Divesoft Freedom */
|
||||
{"Divesoft", "Freedom", DC_FAMILY_DIVESOFT_FREEDOM, 19, DC_TRANSPORT_BLE, dc_filter_divesoft},
|
||||
{"Divesoft", "Liberty", DC_FAMILY_DIVESOFT_FREEDOM, 10, DC_TRANSPORT_BLE, dc_filter_divesoft},
|
||||
|
||||
// Not merged upstream yet
|
||||
/* Garmin -- model numbers as defined in FIT format; USB product id is (0x4000 | model) */
|
||||
/* for the Mk1 we are using the model of the global model */
|
||||
/* for the Mk2/Mk3 we are using the model of the Mk2 global model */
|
||||
/* see garmin_parser.c for a more comprehensive list of models */
|
||||
{"Garmin", "Descent Mk1", DC_FAMILY_GARMIN, 2859, DC_TRANSPORT_USBSTORAGE, NULL},
|
||||
{"Garmin", "Descent Mk2(i)/Mk3(i)", DC_FAMILY_GARMIN, 3258, DC_TRANSPORT_USBSTORAGE, NULL},
|
||||
{"FIT", "File import", DC_FAMILY_GARMIN, 0, DC_TRANSPORT_USBSTORAGE, NULL },
|
||||
/* Garmin */
|
||||
{"Garmin", "Descent Mk1", DC_FAMILY_GARMIN, 2859, DC_TRANSPORT_USBSTORAGE, dc_filter_garmin},
|
||||
{"Garmin", "Descent Mk2", DC_FAMILY_GARMIN, 0x4CBA, DC_TRANSPORT_USBSTORAGE, dc_filter_garmin},
|
||||
/* Deepblu */
|
||||
{"Deepblu", "Cosmiq+", DC_FAMILY_DEEPBLU, 0, DC_TRANSPORT_BLE, dc_filter_deepblu},
|
||||
/* Oceans S1 */
|
||||
{ "Oceans", "S1", DC_FAMILY_OCEANS_S1, 0, DC_TRANSPORT_BLE, dc_filter_oceans },
|
||||
};
|
||||
|
||||
static int
|
||||
@ -518,15 +451,6 @@ dc_match_usb (const void *key, const void *value)
|
||||
return k->vid == v->vid && k->pid == v->pid;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_match_usbhid (const void *key, const void *value)
|
||||
{
|
||||
const dc_usbhid_desc_t *k = (const dc_usbhid_desc_t *) key;
|
||||
const dc_usbhid_desc_t *v = (const dc_usbhid_desc_t *) value;
|
||||
|
||||
return k->vid == v->vid && k->pid == v->pid;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_match_number_with_prefix (const void *key, const void *value)
|
||||
{
|
||||
@ -561,19 +485,20 @@ dc_match_oceanic (const void *key, const void *value)
|
||||
0
|
||||
};
|
||||
|
||||
const char *p = prefix;
|
||||
|
||||
return dc_match_number_with_prefix (key, &p);
|
||||
return dc_match_number_with_prefix (key, &prefix);
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_internal (const void *key, const void *values, size_t count, size_t size, dc_match_t match)
|
||||
dc_filter_internal (const void *key, const void *values, size_t count, size_t size, dc_match_t match, void *params_dst, const void *params_src, size_t params_size)
|
||||
{
|
||||
if (key == NULL)
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
if (match (key, (const unsigned char *) values + i * size)) {
|
||||
if (params_src && params_dst) {
|
||||
memcpy (params_dst, params_src, params_size);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -588,8 +513,7 @@ static const char * const rfcomm[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static int
|
||||
dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, void *params)
|
||||
{
|
||||
static const char * const irda[] = {
|
||||
"Aladin Smart Com",
|
||||
@ -600,8 +524,8 @@ dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const v
|
||||
"UWATEC Galileo",
|
||||
"UWATEC Galileo Sol",
|
||||
};
|
||||
static const dc_usbhid_desc_t usbhid[] = {
|
||||
{0x2e6c, 0x3201}, // G2, G2 TEK
|
||||
static const dc_usb_desc_t usbhid[] = {
|
||||
{0x2e6c, 0x3201}, // G2
|
||||
{0x2e6c, 0x3211}, // G2 Console
|
||||
{0x2e6c, 0x4201}, // G2 HUD
|
||||
{0xc251, 0x2006}, // Aladin Square
|
||||
@ -611,17 +535,12 @@ dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const v
|
||||
"Aladin",
|
||||
"HUD",
|
||||
"A1",
|
||||
"A2",
|
||||
"G2 TEK",
|
||||
"Galileo 3",
|
||||
"Luna 2.0 AI",
|
||||
"Luna 2.0",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_IRDA) {
|
||||
return DC_FILTER_INTERNAL (userdata, irda, 0, dc_match_name);
|
||||
} else if (transport == DC_TRANSPORT_USBHID) {
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usbhid);
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usb);
|
||||
} else if (transport == DC_TRANSPORT_BLE) {
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name);
|
||||
}
|
||||
@ -629,24 +548,21 @@ dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const v
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_suunto (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
static int dc_filter_suunto (dc_transport_t transport, const void *userdata, void *params)
|
||||
{
|
||||
static const dc_usbhid_desc_t usbhid[] = {
|
||||
static const dc_usb_desc_t usbhid[] = {
|
||||
{0x1493, 0x0030}, // Eon Steel
|
||||
{0x1493, 0x0033}, // Eon Core
|
||||
{0x1493, 0x0035}, // D5
|
||||
{0x1493, 0x0036}, // EON Steel Black
|
||||
};
|
||||
static const char * const bluetooth[] = {
|
||||
"EON Steel",
|
||||
"EON Core",
|
||||
"Suunto D5",
|
||||
"EON Steel Black",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_USBHID) {
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usbhid);
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usb);
|
||||
} else if (transport == DC_TRANSPORT_BLE) {
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix);
|
||||
}
|
||||
@ -654,8 +570,7 @@ dc_filter_suunto (dc_descriptor_t *descriptor, dc_transport_t transport, const v
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_hw (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
static int dc_filter_hw (dc_transport_t transport, const void *userdata, void *params)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"OSTC",
|
||||
@ -671,20 +586,16 @@ dc_filter_hw (dc_descriptor_t *descriptor, dc_transport_t transport, const void
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_shearwater (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
static int dc_filter_shearwater (dc_transport_t transport, const void *userdata, void *params)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"Predator",
|
||||
"Petrel",
|
||||
"Petrel 3",
|
||||
"NERD",
|
||||
"NERD 2",
|
||||
"Perdix",
|
||||
"Perdix 2",
|
||||
"Teric",
|
||||
"Peregrine",
|
||||
"Tern"
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
|
||||
@ -696,8 +607,7 @@ dc_filter_shearwater (dc_descriptor_t *descriptor, dc_transport_t transport, con
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_tecdiving (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata, void *params)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"DiveComputer",
|
||||
@ -712,8 +622,7 @@ dc_filter_tecdiving (dc_descriptor_t *descriptor, dc_transport_t transport, cons
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_mares (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
static int dc_filter_mares (dc_transport_t transport, const void *userdata, void *params)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"Mares bluelink pro",
|
||||
@ -727,29 +636,23 @@ dc_filter_mares (dc_descriptor_t *descriptor, dc_transport_t transport, const vo
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_divesystem (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
static int dc_filter_divesystem (dc_transport_t transport, const void *userdata, void *params)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"DS",
|
||||
"IX5M",
|
||||
"RATIO-",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
|
||||
if (transport == DC_TRANSPORT_BLUETOOTH) {
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_number_with_prefix);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, void *params)
|
||||
{
|
||||
static const unsigned int model[] = {
|
||||
0x4552, // Oceanic Pro Plus X
|
||||
0x455A, // Aqualung i750TC
|
||||
0x4647, // Sherwood Sage
|
||||
0x4648, // Aqualung i300C
|
||||
0x4649, // Aqualung i200C
|
||||
0x4651, // Aqualung i770R
|
||||
@ -758,12 +661,7 @@ dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const
|
||||
0x4654, // Oceanic Veo 4.0
|
||||
0x4655, // Sherwood Wisdom 4
|
||||
0x4656, // Oceanic Pro Plus 4
|
||||
0x4741, // Apeks DSX
|
||||
0x4742, // Sherwood Beacon
|
||||
0x4743, // Aqualung i470TC
|
||||
0x4744, // Aqualung i330R
|
||||
0x4749, // Aqualung i200C (newer model)
|
||||
0x474B, // Oceanic Geo Air
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
@ -773,8 +671,7 @@ dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_mclean(dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
static int dc_filter_mclean(dc_transport_t transport, const void *userdata, void *params)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"McLean Extreme",
|
||||
@ -789,39 +686,38 @@ dc_filter_mclean(dc_descriptor_t *descriptor, dc_transport_t transport, const vo
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_atomic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
static int dc_filter_atomic (dc_transport_t transport, const void *userdata, void *params)
|
||||
{
|
||||
static const dc_usb_desc_t usb[] = {
|
||||
{0x0471, 0x0888}, // Atomic Aquatics Cobalt
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_USB) {
|
||||
return DC_FILTER_INTERNAL (userdata, usb, 0, dc_match_usb);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_deepsix (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"EXCURSION",
|
||||
"Crest-CR4",
|
||||
"CENTAURI",
|
||||
"ALPHA",
|
||||
static const dc_usb_params_t usb_params = {
|
||||
0, 0x82, 0x02
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name);
|
||||
if (transport == DC_TRANSPORT_USB) {
|
||||
return DC_FILTER_INTERNAL_WITH_PARAMS (userdata, usb, 0, dc_match_usb, params, &usb_params);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_deepblu (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
// Not merged upstream yet
|
||||
static int dc_filter_garmin (dc_transport_t transport, const void *userdata, void *params)
|
||||
{
|
||||
static const dc_usb_desc_t usbhid[] = {
|
||||
{0x091e, 0x2b2b}, // Garmin Descent Mk1
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_USBSTORAGE) {
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usb);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_deepblu (dc_transport_t transport, const void *userdata, void *params)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"COSMIQ",
|
||||
@ -834,30 +730,14 @@ dc_filter_deepblu (dc_descriptor_t *descriptor, dc_transport_t transport, const
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_oceans (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
static int dc_filter_oceans(dc_transport_t transport, const void* userdata, void *params)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
static const char* const ble[] = {
|
||||
"S1",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_divesoft (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"Freedom",
|
||||
"Liberty",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix);
|
||||
return DC_FILTER_INTERNAL(userdata, ble, 0, dc_match_prefix);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -955,10 +835,10 @@ dc_descriptor_get_transports (dc_descriptor_t *descriptor)
|
||||
}
|
||||
|
||||
int
|
||||
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata, void *params)
|
||||
{
|
||||
if (descriptor == NULL || descriptor->filter == NULL || userdata == NULL)
|
||||
if (descriptor == NULL || descriptor->filter == NULL)
|
||||
return 1;
|
||||
|
||||
return descriptor->filter (descriptor, transport, userdata);
|
||||
return descriptor->filter (transport, userdata, params);
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ int
|
||||
device_is_cancelled (dc_device_t *device);
|
||||
|
||||
dc_status_t
|
||||
device_dump_read (dc_device_t *device, unsigned int address, unsigned char data[], unsigned int size, unsigned int blocksize);
|
||||
device_dump_read (dc_device_t *device, unsigned char data[], unsigned int size, unsigned int blocksize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
43
src/device.c
43
src/device.c
@ -38,7 +38,6 @@
|
||||
#include "oceanic_atom2.h"
|
||||
#include "oceanic_veo250.h"
|
||||
#include "oceanic_vtpro.h"
|
||||
#include "pelagic_i330r.h"
|
||||
#include "mares_darwin.h"
|
||||
#include "mares_iconhd.h"
|
||||
#include "mares_nemo.h"
|
||||
@ -60,15 +59,11 @@
|
||||
#include "tecdiving_divecomputereu.h"
|
||||
#include "mclean_extreme.h"
|
||||
#include "liquivision_lynx.h"
|
||||
#include "sporasub_sp2.h"
|
||||
#include "deepsix_excursion.h"
|
||||
#include "seac_screen.h"
|
||||
#include "deepblu_cosmiq.h"
|
||||
#include "oceans_s1.h"
|
||||
#include "divesoft_freedom.h"
|
||||
|
||||
// Not merged upstream yet
|
||||
#include "garmin.h"
|
||||
#include "deepblu.h"
|
||||
#include "oceans_s1.h"
|
||||
|
||||
#include "device-private.h"
|
||||
#include "context-private.h"
|
||||
@ -166,9 +161,6 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
|
||||
case DC_FAMILY_OCEANIC_ATOM2:
|
||||
rc = oceanic_atom2_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
||||
break;
|
||||
case DC_FAMILY_PELAGIC_I330R:
|
||||
rc = pelagic_i330r_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
||||
break;
|
||||
case DC_FAMILY_MARES_NEMO:
|
||||
rc = mares_nemo_device_open (&device, context, iostream);
|
||||
break;
|
||||
@ -232,24 +224,6 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
|
||||
case DC_FAMILY_LIQUIVISION_LYNX:
|
||||
rc = liquivision_lynx_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_SPORASUB_SP2:
|
||||
rc = sporasub_sp2_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_DEEPSIX_EXCURSION:
|
||||
rc = deepsix_excursion_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_SEAC_SCREEN:
|
||||
rc = seac_screen_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_DEEPBLU_COSMIQ:
|
||||
rc = deepblu_cosmiq_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_OCEANS_S1:
|
||||
rc = oceans_s1_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_DIVESOFT_FREEDOM:
|
||||
rc = divesoft_freedom_device_open (&device, context, iostream);
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
@ -257,6 +231,12 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
|
||||
case DC_FAMILY_GARMIN:
|
||||
rc = garmin_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
||||
break;
|
||||
case DC_FAMILY_DEEPBLU:
|
||||
rc = deepblu_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_OCEANS_S1:
|
||||
rc = oceans_s1_device_open(&device, context, iostream);
|
||||
break;
|
||||
}
|
||||
|
||||
*out = device;
|
||||
@ -370,7 +350,7 @@ dc_device_dump (dc_device_t *device, dc_buffer_t *buffer)
|
||||
|
||||
|
||||
dc_status_t
|
||||
device_dump_read (dc_device_t *device, unsigned int address, unsigned char data[], unsigned int size, unsigned int blocksize)
|
||||
device_dump_read (dc_device_t *device, unsigned char data[], unsigned int size, unsigned int blocksize)
|
||||
{
|
||||
if (device == NULL)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
@ -391,7 +371,7 @@ device_dump_read (dc_device_t *device, unsigned int address, unsigned char data[
|
||||
len = blocksize;
|
||||
|
||||
// Read the packet.
|
||||
dc_status_t rc = device->vtable->read (device, address + nbytes, data + nbytes, len);
|
||||
dc_status_t rc = device->vtable->read (device, nbytes, data + nbytes, len);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
@ -428,9 +408,6 @@ dc_device_timesync (dc_device_t *device, const dc_datetime_t *datetime)
|
||||
if (device->vtable->timesync == NULL)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
|
||||
if (datetime == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
return device->vtable->timesync (device, datetime);
|
||||
}
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
diverite_nitekq_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
diverite_nitekq_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
diverite_nitekq_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@ struct diverite_nitekq_parser_t {
|
||||
double maxdepth;
|
||||
};
|
||||
|
||||
static dc_status_t diverite_nitekq_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
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);
|
||||
@ -56,9 +57,7 @@ static dc_status_t diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract
|
||||
static const dc_parser_vtable_t diverite_nitekq_parser_vtable = {
|
||||
sizeof(diverite_nitekq_parser_t),
|
||||
DC_FAMILY_DIVERITE_NITEKQ,
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
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 */
|
||||
@ -67,7 +66,7 @@ static const dc_parser_vtable_t diverite_nitekq_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
{
|
||||
diverite_nitekq_parser_t *parser = NULL;
|
||||
|
||||
@ -75,7 +74,7 @@ diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context, const u
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (diverite_nitekq_parser_t *) dc_parser_allocate (context, &diverite_nitekq_parser_vtable, data, size);
|
||||
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;
|
||||
@ -99,6 +98,13 @@ diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context, const u
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
diverite_nitekq_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -152,7 +158,6 @@ diverite_nitekq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, u
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = parser->he[flags] / 100.0;
|
||||
gasmix->oxygen = parser->o2[flags] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -256,13 +261,13 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
|
||||
// Time (seconds).
|
||||
time += interval;
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
|
||||
// Gas change
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
@ -274,7 +279,7 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
sample.depth = depth / 10.0;
|
||||
else
|
||||
sample.depth = depth * FEET / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
offset += 2;
|
||||
|
||||
if (type == 3) {
|
||||
@ -285,9 +290,8 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
if (offset + 1 > size)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
unsigned int ppo2 = data[offset];
|
||||
sample.ppo2.sensor = DC_SENSOR_NONE;
|
||||
sample.ppo2.value = ppo2 / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PPO2, &sample, userdata);
|
||||
sample.ppo2 = ppo2 / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
|
||||
offset++;
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -1,595 +0,0 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2023 Jan Matoušek, 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "divesoft_freedom.h"
|
||||
#include "context-private.h"
|
||||
#include "device-private.h"
|
||||
#include "platform.h"
|
||||
#include "checksum.h"
|
||||
#include "array.h"
|
||||
#include "hdlc.h"
|
||||
|
||||
#define MAXDATA 256
|
||||
|
||||
#define HEADER_SIGNATURE_V1 0x45766944 // "DivE"
|
||||
#define HEADER_SIGNATURE_V2 0x45566944 // "DiVE"
|
||||
|
||||
#define HEADER_SIZE_V1 32
|
||||
#define HEADER_SIZE_V2 64
|
||||
|
||||
#define RECORD_SIZE 16
|
||||
#define FINGERPRINT_SIZE 20
|
||||
|
||||
#define INVALID 0xFFFFFFFF
|
||||
#define COMPRESSION 1
|
||||
#define DIRECTION 1
|
||||
#define NRECORDS 100
|
||||
|
||||
#define DEVICE_CCR_CU 1 // Liberty HW rev. 1.X
|
||||
#define DEVICE_FREEDOM 2 // Freedom HW rev. 2.X
|
||||
#define DEVICE_FREEDOM3 5 // Freedom HW rev. 3.X
|
||||
#define DEVICE_CCR_CU15 10 // Liberty HW rev. 2.X, Bluetooth enabled
|
||||
#define DEVICE_FREEDOM4 19 // Freedom HW rev. 4.X, Bluetooth enabled
|
||||
|
||||
typedef enum message_t {
|
||||
MSG_ECHO = 0,
|
||||
MSG_RESULT = 1,
|
||||
MSG_CONNECT = 2,
|
||||
MSG_CONNECTED = 3,
|
||||
MSG_VERSION = 4,
|
||||
MSG_VERSION_RSP = 5,
|
||||
MSG_DIVE_DATA = 64,
|
||||
MSG_DIVE_DATA_RSP = 65,
|
||||
MSG_DIVE_LIST = 66,
|
||||
MSG_DIVE_LIST_V1 = 67,
|
||||
MSG_DIVE_LIST_V2 = 71,
|
||||
} message_t;
|
||||
|
||||
typedef struct divesoft_freedom_device_t {
|
||||
dc_device_t base;
|
||||
dc_iostream_t *iostream;
|
||||
unsigned char fingerprint[FINGERPRINT_SIZE];
|
||||
unsigned int seqnum;
|
||||
} divesoft_freedom_device_t;
|
||||
|
||||
static dc_status_t divesoft_freedom_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||
static dc_status_t divesoft_freedom_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
||||
static dc_status_t divesoft_freedom_device_close (dc_device_t *device);
|
||||
|
||||
static const dc_device_vtable_t divesoft_freedom_device_vtable = {
|
||||
sizeof(divesoft_freedom_device_t),
|
||||
DC_FAMILY_DIVESOFT_FREEDOM,
|
||||
divesoft_freedom_device_set_fingerprint, /* set_fingerprint */
|
||||
NULL, /* read */
|
||||
NULL, /* write */
|
||||
NULL, /* dump */
|
||||
divesoft_freedom_device_foreach, /* foreach */
|
||||
NULL, /* timesync */
|
||||
divesoft_freedom_device_close, /* close */
|
||||
};
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_send (divesoft_freedom_device_t *device, message_t message, const unsigned char data[], size_t size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
size_t nbytes = 0, count = 0;
|
||||
while (1) {
|
||||
size_t len = size - nbytes;
|
||||
if (len > MAXDATA)
|
||||
len = MAXDATA;
|
||||
|
||||
unsigned int islast = nbytes + len == size;
|
||||
|
||||
unsigned char packet[6 + MAXDATA + 2] = {0};
|
||||
packet[0] = ((count & 0x0F) << 4) | (device->seqnum & 0x0F);
|
||||
packet[1] = 0x80 | (islast << 6);
|
||||
array_uint16_le_set (packet + 2, message);
|
||||
array_uint16_le_set (packet + 4, len);
|
||||
if (len) {
|
||||
memcpy (packet + 6, data + nbytes, len);
|
||||
}
|
||||
unsigned short crc = checksum_crc16r_ccitt (packet, len + 6, 0xFFFF, 0xFFFF);
|
||||
array_uint16_le_set (packet + 6 + len, crc);
|
||||
|
||||
HEXDUMP (abstract->context, DC_LOGLEVEL_DEBUG, "cmd", packet, 6 + len + 2);
|
||||
|
||||
status = dc_iostream_write (device->iostream, packet, 6 + len + 2, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the packet.");
|
||||
return status;
|
||||
}
|
||||
|
||||
nbytes += len;
|
||||
count++;
|
||||
|
||||
if (islast)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_recv (divesoft_freedom_device_t *device, dc_event_progress_t *progress, message_t *message, dc_buffer_t *buffer)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
unsigned int msg = INVALID;
|
||||
|
||||
unsigned int count = 0;
|
||||
while (1) {
|
||||
size_t len = 0;
|
||||
unsigned char packet[6 + MAXDATA + 2] = {0};
|
||||
status = dc_iostream_read (device->iostream, packet, sizeof(packet), &len);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the packet.");
|
||||
return status;
|
||||
}
|
||||
|
||||
HEXDUMP (abstract->context, DC_LOGLEVEL_DEBUG, "rcv", packet, len);
|
||||
|
||||
if (len < 8) {
|
||||
ERROR (abstract->context, "Unexpected packet length (" DC_PRINTF_SIZE ").", len);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
unsigned int seqnum = packet[0];
|
||||
unsigned int flags = packet[1];
|
||||
unsigned int type = array_uint16_le (packet + 2);
|
||||
unsigned int length = array_uint16_le (packet + 4);
|
||||
|
||||
unsigned int expected = ((count & 0x0F) << 4) | (device->seqnum & 0x0F);
|
||||
if (seqnum != expected) {
|
||||
ERROR (abstract->context, "Unexpected packet sequence number (%u %u).", seqnum, expected);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if ((flags & ~0x40) != 0) {
|
||||
ERROR (abstract->context, "Unexpected packet flags (%u).", flags);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (length != len - 8) {
|
||||
ERROR (abstract->context, "Unexpected packet length (%u " DC_PRINTF_SIZE ").", length, len - 8);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (msg == INVALID) {
|
||||
msg = type;
|
||||
} else if (msg != type) {
|
||||
ERROR (abstract->context, "Unexpected packet type (%u).", msg);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
unsigned short crc = array_uint16_le (packet + len - 2);
|
||||
unsigned short ccrc = checksum_crc16r_ccitt (packet, len - 2, 0xFFFF, 0xFFFF);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected packet checksum (%04x %04x).", crc, ccrc);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
if (progress) {
|
||||
progress->current += len - 8;
|
||||
// Limit the progress to the maximum size. This could happen if the
|
||||
// dive computer sends more data than requested for some reason.
|
||||
if (progress->current > progress->maximum) {
|
||||
WARNING (abstract->context, "Progress exceeds the maximum size.");
|
||||
progress->current = progress->maximum;
|
||||
}
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
|
||||
}
|
||||
|
||||
if (!dc_buffer_append (buffer, packet + 6, len - 8)) {
|
||||
ERROR (abstract->context, "Insufficient buffer space available.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
if (flags & 0x40)
|
||||
break;
|
||||
}
|
||||
|
||||
if (message)
|
||||
*message = msg;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_transfer (divesoft_freedom_device_t *device, dc_event_progress_t *progress, message_t cmd, const unsigned char data[], size_t size, message_t *msg, dc_buffer_t *buffer)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
if (device_is_cancelled (abstract))
|
||||
return DC_STATUS_CANCELLED;
|
||||
|
||||
device->seqnum++;
|
||||
|
||||
status = divesoft_freedom_send (device, cmd, data, size);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = divesoft_freedom_recv (device, progress, msg, buffer);
|
||||
if(status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive response.");
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_download (divesoft_freedom_device_t *device, message_t cmd, const unsigned char cdata[], size_t csize, unsigned char rdata[], size_t rsize)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
dc_buffer_t *buffer = dc_buffer_new (rsize);
|
||||
if (buffer == NULL) {
|
||||
ERROR (abstract->context, "Failed to allocate memory.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
message_t msg = MSG_ECHO;
|
||||
status = divesoft_freedom_transfer (device, NULL, cmd, cdata, csize, &msg, buffer);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to transfer the packet.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
if (msg != cmd + 1) {
|
||||
ERROR (abstract->context, "Unexpected response message (%u).", msg);
|
||||
status = DC_STATUS_PROTOCOL;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
size_t length = dc_buffer_get_size (buffer);
|
||||
if (length != rsize) {
|
||||
ERROR (abstract->context, "Unexpected response length (" DC_PRINTF_SIZE " " DC_PRINTF_SIZE ").", length, rsize);
|
||||
status = DC_STATUS_PROTOCOL;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
if (rsize) {
|
||||
memcpy (rdata, dc_buffer_get_data (buffer), rsize);
|
||||
}
|
||||
|
||||
error_free:
|
||||
dc_buffer_free (buffer);
|
||||
error_exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
divesoft_freedom_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
divesoft_freedom_device_t *device = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
device = (divesoft_freedom_device_t *) dc_device_allocate (context, &divesoft_freedom_device_vtable);
|
||||
if (device == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
device->iostream = NULL;
|
||||
memset(device->fingerprint, 0, sizeof(device->fingerprint));
|
||||
device->seqnum = 0;
|
||||
|
||||
// Setup the HDLC communication.
|
||||
status = dc_hdlc_open (&device->iostream, context, iostream, 244, 244);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to create the HDLC stream.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Set the serial communication protocol (115200 8N1).
|
||||
status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the terminal attributes.");
|
||||
goto error_free_hdlc;
|
||||
}
|
||||
|
||||
// Set the timeout for receiving data (3000ms).
|
||||
status = dc_iostream_set_timeout (device->iostream, 3000);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the timeout.");
|
||||
goto error_free_hdlc;
|
||||
}
|
||||
|
||||
// Initiate the connection with the dive computer.
|
||||
const char client[] = "libdivecomputer";
|
||||
unsigned char cmd_connect[2 + sizeof(client) - 1] = {0};
|
||||
array_uint16_le_set (cmd_connect, COMPRESSION);
|
||||
memcpy (cmd_connect + 2, client, sizeof(client) - 1);
|
||||
unsigned char rsp_connect[36] = {0};
|
||||
status = divesoft_freedom_download (device, MSG_CONNECT, cmd_connect, sizeof(cmd_connect), rsp_connect, sizeof(rsp_connect));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to connect to the device.");
|
||||
goto error_free_hdlc;
|
||||
}
|
||||
|
||||
DEBUG (context, "Connection: compression=%u, protocol=%u.%u, serial=%.16s",
|
||||
array_uint16_le (rsp_connect),
|
||||
rsp_connect[2], rsp_connect[3],
|
||||
rsp_connect + 4);
|
||||
|
||||
*out = (dc_device_t *) device;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free_hdlc:
|
||||
dc_iostream_close (device->iostream);
|
||||
error_free:
|
||||
dc_device_deallocate ((dc_device_t *) device);
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_device_close (dc_device_t *abstract)
|
||||
{
|
||||
divesoft_freedom_device_t *device = (divesoft_freedom_device_t *) abstract;
|
||||
|
||||
return dc_iostream_close (device->iostream);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
|
||||
{
|
||||
divesoft_freedom_device_t *device = (divesoft_freedom_device_t *) abstract;
|
||||
|
||||
if (size && size != sizeof (device->fingerprint))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (size)
|
||||
memcpy (device->fingerprint, data, sizeof (device->fingerprint));
|
||||
else
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
divesoft_freedom_device_t *device = (divesoft_freedom_device_t *) abstract;
|
||||
|
||||
// Enable progress notifications.
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
// Read the device information.
|
||||
unsigned char rsp_version[26] = {0};
|
||||
status = divesoft_freedom_download (device, MSG_VERSION, NULL, 0, rsp_version, sizeof(rsp_version));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the device information.");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
DEBUG (abstract->context, "Device: model=%u, hw=%u.%u, sw=%u.%u.%u.%u serial=%.16s",
|
||||
rsp_version[0],
|
||||
rsp_version[1], rsp_version[2],
|
||||
rsp_version[3], rsp_version[4], rsp_version[5],
|
||||
array_uint32_le (rsp_version + 6),
|
||||
rsp_version + 10);
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = rsp_version[0];
|
||||
devinfo.firmware = array_uint24_be (rsp_version + 3);
|
||||
devinfo.serial = array_convert_str2num (rsp_version + 10 + 5, 11);
|
||||
device_event_emit(abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
// Allocate memory for the dive list.
|
||||
dc_buffer_t *divelist = dc_buffer_new (0);
|
||||
if (divelist == NULL) {
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// Allocate memory for the download buffer.
|
||||
dc_buffer_t *buffer = dc_buffer_new (NRECORDS * (4 + FINGERPRINT_SIZE + HEADER_SIZE_V2));
|
||||
if (buffer == NULL) {
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free_divelist;
|
||||
}
|
||||
|
||||
// Record version and size.
|
||||
unsigned int version = 0;
|
||||
unsigned int headersize = 0;
|
||||
unsigned int recordsize = 0;
|
||||
|
||||
// Download the dive list.
|
||||
unsigned int ndives = 0;
|
||||
unsigned int total = 0;
|
||||
unsigned int maxsize = 0;
|
||||
unsigned int current = INVALID;
|
||||
while (1) {
|
||||
// Clear the buffer.
|
||||
dc_buffer_clear (buffer);
|
||||
|
||||
// Prepare the command.
|
||||
unsigned char cmd_list[6] = {0};
|
||||
array_uint32_le_set (cmd_list, current);
|
||||
cmd_list[4] = DIRECTION;
|
||||
cmd_list[5] = NRECORDS;
|
||||
|
||||
// Download the dive list records.
|
||||
message_t msg_list = MSG_ECHO;
|
||||
status = divesoft_freedom_transfer (device, &progress, MSG_DIVE_LIST, cmd_list, sizeof(cmd_list), &msg_list, buffer);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to download the dive list.");
|
||||
goto error_free_buffer;
|
||||
}
|
||||
|
||||
// Check the response message type.
|
||||
if (msg_list != MSG_DIVE_LIST_V1 && msg_list != MSG_DIVE_LIST_V2) {
|
||||
ERROR (abstract->context, "Unexpected response message (%u).", msg_list);
|
||||
status = DC_STATUS_PROTOCOL;
|
||||
goto error_free_buffer;
|
||||
}
|
||||
|
||||
// Store/check the version.
|
||||
if (version == 0) {
|
||||
version = msg_list;
|
||||
headersize = version == MSG_DIVE_LIST_V1 ?
|
||||
HEADER_SIZE_V1 : HEADER_SIZE_V2;
|
||||
recordsize = 4 + FINGERPRINT_SIZE + headersize;
|
||||
} else if (version != msg_list) {
|
||||
ERROR (abstract->context, "Unexpected response message (%u).", msg_list);
|
||||
status = DC_STATUS_PROTOCOL;
|
||||
goto error_free_buffer;
|
||||
}
|
||||
|
||||
const unsigned char *data = dc_buffer_get_data (buffer);
|
||||
size_t size = dc_buffer_get_size (buffer);
|
||||
|
||||
// Process the records.
|
||||
size_t offset = 0, count = 0;
|
||||
while (offset + recordsize <= size) {
|
||||
// Get the record data.
|
||||
unsigned int handle = array_uint32_le (data + offset);
|
||||
const unsigned char *fingerprint = data + offset + 4;
|
||||
const unsigned char *header = data + offset + 4 + FINGERPRINT_SIZE;
|
||||
|
||||
// Check the fingerprint data.
|
||||
if (memcmp (device->fingerprint, fingerprint, sizeof(device->fingerprint)) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the length of the dive.
|
||||
unsigned int nrecords = version == MSG_DIVE_LIST_V1 ?
|
||||
array_uint32_le (header + 16) & 0x3FFFF :
|
||||
array_uint32_le (header + 20);
|
||||
unsigned int length = headersize + nrecords * RECORD_SIZE;
|
||||
|
||||
// Calculate the total and maximum size.
|
||||
if (length > maxsize)
|
||||
maxsize = length;
|
||||
total += length;
|
||||
|
||||
// Set the handle for the next request.
|
||||
current = handle;
|
||||
|
||||
offset += recordsize;
|
||||
count++;
|
||||
ndives++;
|
||||
}
|
||||
|
||||
// Append the records to the dive list buffer.
|
||||
if (!dc_buffer_append (divelist, data, count * recordsize)) {
|
||||
ERROR (abstract->context, "Insufficient buffer space available.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free_buffer;
|
||||
}
|
||||
|
||||
// Stop downloading if there are no more records.
|
||||
if (count < NRECORDS)
|
||||
break;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.maximum = progress.current + total;
|
||||
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
// Reserve memory for the largest dive.
|
||||
dc_buffer_reserve (buffer, maxsize);
|
||||
|
||||
const unsigned char *data = dc_buffer_get_data (divelist);
|
||||
size_t size = dc_buffer_get_size (divelist);
|
||||
|
||||
size_t offset = 0;
|
||||
while (offset + recordsize <= size) {
|
||||
// Get the record data.
|
||||
unsigned int handle = array_uint32_le (data + offset);
|
||||
const unsigned char *fingerprint = data + offset + 4;
|
||||
const unsigned char *header = data + offset + 4 + FINGERPRINT_SIZE;
|
||||
|
||||
// Get the length of the dive.
|
||||
unsigned int nrecords = version == MSG_DIVE_LIST_V1 ?
|
||||
array_uint32_le (header + 16) & 0x3FFFF :
|
||||
array_uint32_le (header + 20);
|
||||
unsigned int length = headersize + nrecords * RECORD_SIZE;
|
||||
|
||||
// Clear the buffer.
|
||||
dc_buffer_clear (buffer);
|
||||
|
||||
// Prepare the command.
|
||||
unsigned char cmd_dive[12] = {0};
|
||||
array_uint32_le_set (cmd_dive + 0, handle);
|
||||
array_uint32_le_set (cmd_dive + 4, 0);
|
||||
array_uint32_le_set (cmd_dive + 8, length);
|
||||
|
||||
// Download the dive.
|
||||
message_t msg_dive = MSG_ECHO;
|
||||
status = divesoft_freedom_transfer (device, &progress, MSG_DIVE_DATA, cmd_dive, sizeof(cmd_dive), &msg_dive, buffer);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to download the dive.");
|
||||
goto error_free_buffer;
|
||||
}
|
||||
|
||||
// Check the response message type.
|
||||
if (msg_dive != MSG_DIVE_DATA_RSP) {
|
||||
ERROR (abstract->context, "Unexpected response message (%u).", msg_dive);
|
||||
status = DC_STATUS_PROTOCOL;
|
||||
goto error_free_buffer;
|
||||
}
|
||||
|
||||
// Verify both dive headers are identical.
|
||||
if (dc_buffer_get_size (buffer) < headersize ||
|
||||
memcmp (header, dc_buffer_get_data (buffer), headersize) != 0) {
|
||||
ERROR (abstract->context, "Unexpected profile header.");
|
||||
status = DC_STATUS_PROTOCOL;
|
||||
goto error_free_buffer;
|
||||
}
|
||||
|
||||
if (callback && !callback (dc_buffer_get_data(buffer), dc_buffer_get_size(buffer), fingerprint, sizeof (device->fingerprint), userdata)) {
|
||||
break;
|
||||
}
|
||||
|
||||
offset += recordsize;
|
||||
}
|
||||
|
||||
error_free_buffer:
|
||||
dc_buffer_free (buffer);
|
||||
error_free_divelist:
|
||||
dc_buffer_free (divelist);
|
||||
error_exit:
|
||||
return status;
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2023 Jan Matoušek, 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 DIVESOFT_FREEDOM_H
|
||||
#define DIVESOFT_FREEDOM_H
|
||||
|
||||
#include <libdivecomputer/context.h>
|
||||
#include <libdivecomputer/iostream.h>
|
||||
#include <libdivecomputer/device.h>
|
||||
#include <libdivecomputer/parser.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
dc_status_t
|
||||
divesoft_freedom_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
divesoft_freedom_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* DIVESOFT_FREEDOM_H */
|
||||
File diff suppressed because it is too large
Load Diff
@ -29,7 +29,8 @@
|
||||
#include "platform.h"
|
||||
#include "checksum.h"
|
||||
#include "array.h"
|
||||
#include "packet.h"
|
||||
|
||||
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
|
||||
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &divesystem_idive_device_vtable)
|
||||
|
||||
@ -103,7 +104,6 @@ typedef struct divesystem_idive_device_t {
|
||||
static dc_status_t divesystem_idive_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||
static dc_status_t divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
||||
static dc_status_t divesystem_idive_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime);
|
||||
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),
|
||||
@ -114,7 +114,7 @@ static const dc_device_vtable_t divesystem_idive_device_vtable = {
|
||||
NULL, /* dump */
|
||||
divesystem_idive_device_foreach, /* foreach */
|
||||
divesystem_idive_device_timesync, /* timesync */
|
||||
divesystem_idive_device_close /* close */
|
||||
NULL /* close */
|
||||
};
|
||||
|
||||
static const divesystem_idive_commands_t idive = {
|
||||
@ -154,7 +154,6 @@ divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, dc_iostr
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
divesystem_idive_device_t *device = NULL;
|
||||
dc_transport_t transport = dc_iostream_get_transport (iostream);
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
@ -167,32 +166,22 @@ divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, dc_iostr
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
device->iostream = iostream;
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
device->model = model;
|
||||
|
||||
// Create the packet stream.
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
status = dc_packet_open (&device->iostream, context, iostream, 244, 244);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to create the packet stream.");
|
||||
goto error_free;
|
||||
}
|
||||
} else {
|
||||
device->iostream = iostream;
|
||||
}
|
||||
|
||||
// Set the serial communication protocol (115200 8N1).
|
||||
status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the terminal attributes.");
|
||||
goto error_free_iostream;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Set the timeout for receiving data (1000ms).
|
||||
status = dc_iostream_set_timeout (device->iostream, 1000);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the timeout.");
|
||||
goto error_free_iostream;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Make sure everything is in a sane state.
|
||||
@ -203,27 +192,11 @@ divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, dc_iostr
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free_iostream:
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
dc_iostream_close (device->iostream);
|
||||
}
|
||||
error_free:
|
||||
dc_device_deallocate ((dc_device_t *) device);
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesystem_idive_device_close (dc_device_t *abstract)
|
||||
{
|
||||
divesystem_idive_device_t *device = (divesystem_idive_device_t *) abstract;
|
||||
|
||||
// Close the packet stream.
|
||||
if (dc_iostream_get_transport (device->iostream) == DC_TRANSPORT_BLE) {
|
||||
return dc_iostream_close (device->iostream);
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesystem_idive_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
|
||||
@ -260,7 +233,7 @@ divesystem_idive_send (divesystem_idive_device_t *device, const unsigned char co
|
||||
packet[0] = START;
|
||||
packet[1] = csize;
|
||||
memcpy(packet + 2, command, csize);
|
||||
crc = checksum_crc16_ccitt (packet, csize + 2, 0xffff, 0x0000);
|
||||
crc = checksum_crc16_ccitt (packet, csize + 2, 0xffff);
|
||||
packet[csize + 2] = (crc >> 8) & 0xFF;
|
||||
packet[csize + 3] = (crc ) & 0xFF;
|
||||
|
||||
@ -321,7 +294,7 @@ divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answe
|
||||
|
||||
// Verify the checksum.
|
||||
unsigned short crc = array_uint16_be (packet + len + 2);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (packet, len + 2, 0xffff, 0x0000);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (packet, len + 2, 0xffff);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected packet checksum.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
@ -637,6 +610,11 @@ divesystem_idive_device_timesync (dc_device_t *abstract, const dc_datetime_t *da
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (datetime == NULL) {
|
||||
ERROR (abstract->context, "Invalid parameter specified.");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
// Get the UTC timestamp.
|
||||
dc_ticks_t timestamp = dc_datetime_mktime(datetime);
|
||||
if (timestamp == -1) {
|
||||
@ -925,9 +903,6 @@ divesystem_idive_device_fwupdate (dc_device_t *abstract, const char *filename)
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Wait before sending the firmware data.
|
||||
dc_iostream_sleep (device->iostream, 100);
|
||||
|
||||
// Upload the firmware.
|
||||
unsigned int offset = 0;
|
||||
while (offset + 2 <= size) {
|
||||
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
divesystem_idive_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
divesystem_idive_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
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