Compare commits

..

No commits in common. "Subsurface-DS9" and "crashFix" have entirely different histories.

201 changed files with 5642 additions and 13464 deletions

View File

@ -19,7 +19,7 @@ jobs:
CC: ${{ matrix.compiler }} CC: ${{ matrix.compiler }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v2
- name: Install dependencies - name: Install dependencies
run: sudo apt-get install libbluetooth-dev libusb-1.0-0-dev run: sudo apt-get install libbluetooth-dev libusb-1.0-0-dev
- run: autoreconf --install --force - run: autoreconf --install --force
@ -30,7 +30,7 @@ jobs:
run: | run: |
make install DESTDIR=$PWD/artifacts make install DESTDIR=$PWD/artifacts
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v2
with: with:
name: ${{ github.job }}-${{ matrix.compiler }} name: ${{ github.job }}-${{ matrix.compiler }}
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
@ -50,7 +50,7 @@ jobs:
CC: ${{ matrix.compiler }} CC: ${{ matrix.compiler }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v2
- name: Install dependencies - name: Install dependencies
run: brew install autoconf automake libtool hidapi libusb run: brew install autoconf automake libtool hidapi libusb
- run: autoreconf --install --force - run: autoreconf --install --force
@ -61,7 +61,7 @@ jobs:
run: | run: |
make install DESTDIR=$PWD/artifacts make install DESTDIR=$PWD/artifacts
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v2
with: with:
name: ${{ github.job }}-${{ matrix.compiler }} name: ${{ github.job }}-${{ matrix.compiler }}
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
@ -78,96 +78,18 @@ jobs:
arch: [i686, x86_64] arch: [i686, x86_64]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v2
- name: Install dependencies - name: Install dependencies
run: sudo apt-get install gcc-mingw-w64 binutils-mingw-w64 mingw-w64-tools 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: autoreconf --install --force
- run: ./configure --host=${{ matrix.arch }}-w64-mingw32 --prefix=/usr - 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
- run: make distcheck - run: make distcheck
- name: Package artifacts - name: Package artifacts
run: | run: |
make install DESTDIR=$PWD/artifacts make install DESTDIR=$PWD/artifacts
tar -czf ${{ github.job }}-${{ matrix.arch }}.tar.gz -C artifacts usr tar -czf ${{ github.job }}-${{ matrix.arch }}.tar.gz -C artifacts usr
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v2
with: with:
name: ${{ github.job }}-${{ matrix.arch }} name: ${{ github.job }}-${{ matrix.arch }}
path: ${{ github.job }}-${{ matrix.arch }}.tar.gz 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

View File

@ -9,13 +9,19 @@ jobs:
name: Release name: Release
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v2
- name: Version number - name: Version number
id: version id: version
run: | run: |
VERSION="${GITHUB_REF/refs\/tags\/v/}" VERSION="${GITHUB_REF/refs\/tags\/v/}"
echo "version=${VERSION}" >> $GITHUB_OUTPUT if [ "${VERSION}" = "${VERSION%%-*}" ]; then
PRERELEASE=false
else
PRERELEASE=true
fi
echo ::set-output name=version::${VERSION}
echo ::set-output name=prerelease::${PRERELEASE}
- name: Build distribution tarball - name: Build distribution tarball
id: build id: build
@ -35,13 +41,21 @@ jobs:
exit 1 exit 1
fi fi
- name: Create Github release - uses: actions/create-release@v1
id: 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: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
prerelease: ${{ steps.version.outputs.prerelease }}
- uses: actions/upload-release-asset@v1
id: upload
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.release.outputs.upload_url }}
asset_path: libdivecomputer-${{ steps.version.outputs.version }}.tar.gz
asset_name: libdivecomputer-${{ steps.version.outputs.version }}.tar.gz
asset_content_type: application/gzip

5
.gitignore vendored
View File

@ -47,10 +47,11 @@ Makefile.in
/m4/ltsugar.m4 /m4/ltsugar.m4
/m4/ltversion.m4 /m4/ltversion.m4
/msvc/x64/ /msvc/Debug/
/msvc/x86/ /msvc/Release/
/msvc/*.ncb /msvc/*.ncb
/msvc/*.suo /msvc/*.suo
/msvc/*.vcproj.*.user
/src/libdivecomputer.exp /src/libdivecomputer.exp
/src/libdivecomputer.la /src/libdivecomputer.la

View File

@ -16,8 +16,4 @@ pkgconfig_DATA = libdivecomputer.pc
EXTRA_DIST = \ EXTRA_DIST = \
libdivecomputer.pc.in \ libdivecomputer.pc.in \
contrib/README \ msvc/libdivecomputer.vcproj
contrib/android/Android.mk \
contrib/msvc/libdivecomputer.vcxproj \
contrib/msvc/libdivecomputer.vcxproj.filters \
contrib/udev/libdivecomputer.rules

74
NEWS
View File

@ -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) Version 0.6.0 (2017-11-24)
========================== ==========================

View File

@ -1,6 +1,6 @@
# Versioning. # Versioning.
m4_define([dc_version_major],[0]) 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_micro],[0])
m4_define([dc_version_suffix],[devel-Subsurface-NG]) 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])) m4_define([dc_version],dc_version_major.dc_version_minor.dc_version_micro[]m4_ifset([dc_version_suffix],-[dc_version_suffix]))
@ -120,12 +120,12 @@ AS_IF([test "x$with_libmtp" != "xno"], [
AC_ARG_WITH([hidapi], AC_ARG_WITH([hidapi],
[AS_HELP_STRING([--without-hidapi], [AS_HELP_STRING([--without-hidapi],
[Build without the hidapi library])], [Build without the hidapi library])],
[], [with_hidapi=hidapi]) [], [with_hidapi=auto])
AS_IF([test "x$with_hidapi" != "xno"], [ 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"], [ AS_IF([test "x$have_hidapi" = "xyes"], [
AC_DEFINE([HAVE_HIDAPI], [1], [hidapi library]) AC_DEFINE([HAVE_HIDAPI], [1], [hidapi library])
DEPENDENCIES="$DEPENDENCIES $with_hidapi" DEPENDENCIES="$DEPENDENCIES hidapi"
]) ])
]) ])
@ -170,7 +170,7 @@ AC_CHECK_HEADERS([sys/socket.h linux/types.h linux/irda.h], , , [
# Checks for header files. # Checks for header files.
AC_CHECK_HEADERS([linux/serial.h]) AC_CHECK_HEADERS([linux/serial.h])
AC_CHECK_HEADERS([IOKit/serial/ioss.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([sys/param.h])
AC_CHECK_HEADERS([pthread.h]) AC_CHECK_HEADERS([pthread.h])
AC_CHECK_HEADERS([mach/mach_time.h]) AC_CHECK_HEADERS([mach/mach_time.h])
@ -207,8 +207,6 @@ AX_APPEND_COMPILE_FLAGS([ \
-Wno-unused-but-set-variable \ -Wno-unused-but-set-variable \
-Wno-pointer-sign \ -Wno-pointer-sign \
-Wno-shadow \ -Wno-shadow \
-Wenum-conversion \
-Werror=enum-conversion \
-fmacro-prefix-map='$(top_srcdir)/'= \ -fmacro-prefix-map='$(top_srcdir)/'= \
],,[$ERROR_CFLAGS]) ],,[$ERROR_CFLAGS])
@ -255,6 +253,7 @@ AC_CONFIG_FILES([
include/libdivecomputer/Makefile include/libdivecomputer/Makefile
include/libdivecomputer/version.h include/libdivecomputer/version.h
src/Makefile src/Makefile
src/libdivecomputer.rc
doc/Makefile doc/Makefile
doc/doxygen.cfg doc/doxygen.cfg
doc/man/Makefile doc/man/Makefile

View File

@ -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.

View File

@ -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)

View File

@ -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 &gt; "$(OutDir)libdivecomputer.def" &amp;&amp; type "%(FullPath)" &gt;&gt; "$(OutDir)libdivecomputer.def"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">echo EXPORTS &gt; "$(OutDir)libdivecomputer.def" &amp;&amp; type "%(FullPath)" &gt;&gt; "$(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 &gt; "$(OutDir)libdivecomputer.def" &amp;&amp; type "%(FullPath)" &gt;&gt; "$(OutDir)libdivecomputer.def"</Command>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">echo EXPORTS &gt; "$(OutDir)libdivecomputer.def" &amp;&amp; type "%(FullPath)" &gt;&gt; "$(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>

View File

@ -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>

View File

@ -1,35 +1,23 @@
# Atomic Aquatics Cobalt # Atomic Aquatics Cobalt
SUBSYSTEM=="usb", ATTR{idVendor}=="0471", ATTR{idProduct}=="0888", GROUP="plugdev" SUBSYSTEM=="usb", ATTR{idVendor}=="0471", ATTR{idProduct}=="0888", GROUP="plugdev"
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0471", ATTRS{idProduct}=="0888", GROUP="plugdev"
# Suunto EON Steel # Suunto EON Steel
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0030", GROUP="plugdev" SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0030", GROUP="plugdev"
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0030", GROUP="plugdev"
# Suunto EON Core # Suunto EON Core
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0033", GROUP="plugdev" SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0033", GROUP="plugdev"
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0033", GROUP="plugdev"
# Suunto D5 # Suunto D5
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0035", GROUP="plugdev" 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 # Scubapro G2
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3201", GROUP="plugdev" SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3201", GROUP="plugdev"
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2e6c", ATTRS{idProduct}=="3201", GROUP="plugdev"
# Scubapro G2 Console # Scubapro G2 Console
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3211", GROUP="plugdev" SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3211", GROUP="plugdev"
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2e6c", ATTRS{idProduct}=="3211", GROUP="plugdev"
# Scubapro G2 HUD # Scubapro G2 HUD
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="4201", GROUP="plugdev" SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="4201", GROUP="plugdev"
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2e6c", ATTRS{idProduct}=="4201", GROUP="plugdev"
# Scubapro Aladin Square # Scubapro Aladin Square
SUBSYSTEM=="usb", ATTR{idVendor}=="c251", ATTR{idProduct}=="2006", GROUP="plugdev" SUBSYSTEM=="usb", ATTR{idVendor}=="c251", ATTR{idProduct}=="2006", GROUP="plugdev"
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2006", GROUP="plugdev"

View File

@ -32,6 +32,7 @@ MANPAGES = \
dc_parser_get_field.3 \ dc_parser_get_field.3 \
dc_parser_new.3 \ dc_parser_new.3 \
dc_parser_samples_foreach.3 \ dc_parser_samples_foreach.3 \
dc_parser_set_data.3 \
dc_bluetooth_open.3 \ dc_bluetooth_open.3 \
dc_bluetooth_iterator_new.3 \ dc_bluetooth_iterator_new.3 \
dc_bluetooth_device_get_address.3 \ dc_bluetooth_device_get_address.3 \

View File

@ -82,7 +82,7 @@ is
.Sh SEE ALSO .Sh SEE ALSO
.Xr dc_datetime_localtime 3 , .Xr dc_datetime_localtime 3 ,
.Xr dc_datetime_mktime 3 , .Xr dc_datetime_mktime 3 ,
.Xr dc_datetime_now 3 .Xr dc_datetime_new 3
.Sh AUTHORS .Sh AUTHORS
The The
.Lb libdivecomputer .Lb libdivecomputer

View File

@ -82,7 +82,7 @@ is
.Sh SEE ALSO .Sh SEE ALSO
.Xr dc_datetime_gmtime 3 , .Xr dc_datetime_gmtime 3 ,
.Xr dc_datetime_mktime 3 , .Xr dc_datetime_mktime 3 ,
.Xr dc_datetime_now 3 .Xr dc_datetime_new 3
.Sh AUTHORS .Sh AUTHORS
The The
.Lb libdivecomputer .Lb libdivecomputer

View File

@ -47,7 +47,7 @@ may not sanely be converted.
.Sh SEE ALSO .Sh SEE ALSO
.Xr dc_datetime_gmtime 3 , .Xr dc_datetime_gmtime 3 ,
.Xr dc_datetime_localtime 3 , .Xr dc_datetime_localtime 3 ,
.Xr dc_datetime_now 3 .Xr dc_datetime_new 3
.Sh AUTHORS .Sh AUTHORS
The The
.Lb libdivecomputer .Lb libdivecomputer

View File

@ -53,7 +53,7 @@ with
Each dive invokes Each dive invokes
.Fa callback .Fa callback
with the dive data, which should be parsed with 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. and the binary fingerprint of the dive.
The fingerprint can be used to record the newest dive and stop The fingerprint can be used to record the newest dive and stop
processing (on subsequent invocations) when the same dive fingerprint is 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 returns zero, this will not be reflected in the return value (usually
.Dv DC_STATUS_SUCCESS ) . .Dv DC_STATUS_SUCCESS ) .
.Sh SEE ALSO .Sh SEE ALSO
.Xr dc_parser_new 3 .Xr dc_parser_set_data 3
.Sh AUTHORS .Sh AUTHORS
The The
.Lb libdivecomputer .Lb libdivecomputer

View File

@ -37,7 +37,7 @@
Extract the date and time of a dive, Extract the date and time of a dive,
.Fa parser , .Fa parser ,
previously initialised with 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 This returns the broken-down time-stamp of the dive in the local time of
the dive. the dive.
.Pp .Pp
@ -57,7 +57,7 @@ messages on further failure.
.Sh SEE ALSO .Sh SEE ALSO
.Xr dc_datetime_gmtime 3 , .Xr dc_datetime_gmtime 3 ,
.Xr dc_datetime_localtime 3 , .Xr dc_datetime_localtime 3 ,
.Xr dc_parser_new 3 .Xr dc_parser_set_data 3
.Sh AUTHORS .Sh AUTHORS
The The
.Lb libdivecomputer .Lb libdivecomputer

View File

@ -39,7 +39,7 @@
Extract a field from a dive, Extract a field from a dive,
.Fa parser , .Fa parser ,
previously initialised with previously initialised with
.Xr dc_parser_new 3 . .Xr dc_parser_set_data 3 .
The The
.Fa value .Fa value
field type depends upon the 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 if the field is not supported by the device, or other error messages on
further failure. further failure.
.Sh SEE ALSO .Sh SEE ALSO
.Xr dc_parser_new 3 .Xr dc_parser_set_data 3
.Sh AUTHORS .Sh AUTHORS
The The
.Lb libdivecomputer .Lb libdivecomputer

View File

@ -39,6 +39,8 @@
.Fa "dc_parser_t **parser" .Fa "dc_parser_t **parser"
.Fa "dc_context_t *context" .Fa "dc_context_t *context"
.Fa "dc_descriptor_t *descriptor" .Fa "dc_descriptor_t *descriptor"
.Fa "unsigned int devtime"
.Fa "dc_ticks_t systime"
.Fc .Fc
.Sh DESCRIPTION .Sh DESCRIPTION
Creates a parser for a single dive extracted from the dive computer with Creates a parser for a single dive extracted from the dive computer with
@ -53,6 +55,10 @@ parameter; and
.Nm dc_parser_new2 , .Nm dc_parser_new2 ,
which is given device values (model, etc.) directly. which is given device values (model, etc.) directly.
.Pp .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 The pointer must later be freed with
.Xr dc_parser_destroy 3 . .Xr dc_parser_destroy 3 .
.Sh RETURN VALUES .Sh RETURN VALUES

View File

@ -31,7 +31,7 @@
.Ft "typedef void" .Ft "typedef void"
.Fo "(*dc_sample_callback_t)" .Fo "(*dc_sample_callback_t)"
.Fa "dc_sample_type_t type" .Fa "dc_sample_type_t type"
.Fa "const dc_sample_value_t *value" .Fa "dc_sample_value_t value"
.Fa "void *userdata" .Fa "void *userdata"
.Fc .Fc
.Ft dc_status_t .Ft dc_status_t
@ -42,7 +42,7 @@
.Fc .Fc
.Sh DESCRIPTION .Sh DESCRIPTION
Extract the samples taken during a dive as previously initialised with 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 Each sample is passed to
.Fa callback .Fa callback
with the with the
@ -63,7 +63,7 @@ closed.
The following sample types may be raised: The following sample types may be raised:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Dv DC_SAMPLE_TIME .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 Set in the
.Fa time .Fa time
field. field.
@ -184,7 +184,7 @@ Returns
.Dv DC_STATUS_OK .Dv DC_STATUS_OK
on success and another code on failure. on success and another code on failure.
.Sh SEE ALSO .Sh SEE ALSO
.Xr dc_parser_new 3 .Xr dc_parser_set_data 3
.Sh AUTHORS .Sh AUTHORS
The The
.Lb libdivecomputer .Lb libdivecomputer

View 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 .

View File

@ -82,7 +82,9 @@ Iterate over all dives with
.Xr dc_device_foreach 3 . .Xr dc_device_foreach 3 .
.It .It
For each iterated dive, create a new parser with 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 .It
Get attributes of the parsed dive with Get attributes of the parsed dive with
.Xr dc_parser_get_field 3 . .Xr dc_parser_get_field 3 .

View File

@ -72,7 +72,6 @@ static const backend_table_t g_backends[] = {
{"vtpro", DC_FAMILY_OCEANIC_VTPRO, 0x4245}, {"vtpro", DC_FAMILY_OCEANIC_VTPRO, 0x4245},
{"veo250", DC_FAMILY_OCEANIC_VEO250, 0x424C}, {"veo250", DC_FAMILY_OCEANIC_VEO250, 0x424C},
{"atom2", DC_FAMILY_OCEANIC_ATOM2, 0x4342}, {"atom2", DC_FAMILY_OCEANIC_ATOM2, 0x4342},
{"i330r", DC_FAMILY_PELAGIC_I330R, 0x4744},
{"nemo", DC_FAMILY_MARES_NEMO, 0}, {"nemo", DC_FAMILY_MARES_NEMO, 0},
{"puck", DC_FAMILY_MARES_PUCK, 7}, {"puck", DC_FAMILY_MARES_PUCK, 7},
{"darwin", DC_FAMILY_MARES_DARWIN, 0}, {"darwin", DC_FAMILY_MARES_DARWIN, 0},
@ -92,17 +91,14 @@ static const backend_table_t g_backends[] = {
{"idive", DC_FAMILY_DIVESYSTEM_IDIVE, 0x03}, {"idive", DC_FAMILY_DIVESYSTEM_IDIVE, 0x03},
{"cochran", DC_FAMILY_COCHRAN_COMMANDER, 0}, {"cochran", DC_FAMILY_COCHRAN_COMMANDER, 0},
{"divecomputereu", DC_FAMILY_TECDIVING_DIVECOMPUTEREU, 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}, {"lynx", DC_FAMILY_LIQUIVISION_LYNX, 0},
{"sp2", DC_FAMILY_SPORASUB_SP2, 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 // Not merged upstream yet
{"descentmk1", DC_FAMILY_GARMIN, 0}, {"descentmk1", DC_FAMILY_GARMIN, 0},
{"cosmiq", DC_FAMILY_DEEPBLU, 0},
{"oceans", DC_FAMILY_OCEANS_S1, 0},
}; };
static const transport_table_t g_transports[] = { static const transport_table_t g_transports[] = {

View File

@ -24,12 +24,10 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <signal.h> #include <signal.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_GETOPT_H #ifdef HAVE_GETOPT_H
#include <getopt.h> #include <getopt.h>
#endif #endif
@ -50,7 +48,7 @@
#define RESET 1 #define RESET 1
#endif #endif
#if defined(__GLIBC__) || defined(__MINGW32__) || defined(BSD) || defined(__ANDROID__) #if defined(__GLIBC__) || defined(__MINGW32__) || defined(BSD)
#define NOPERMUTATION "+" #define NOPERMUTATION "+"
#else #else
#define NOPERMUTATION "" #define NOPERMUTATION ""

View File

@ -24,11 +24,9 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_GETOPT_H #ifdef HAVE_GETOPT_H
#include <getopt.h> #include <getopt.h>
#endif #endif
@ -80,12 +78,20 @@ dive_cb (const unsigned char *data, unsigned int size, const unsigned char *fing
// Create the parser. // Create the parser.
message ("Creating the parser.\n"); 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) { if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error creating the parser."); ERROR ("Error creating the parser.");
goto cleanup; 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. // Parse the dive data.
message ("Parsing the dive data.\n"); message ("Parsing the dive data.\n");
rc = dctool_output_write (divedata->output, parser, data, size, fingerprint, fsize); rc = dctool_output_write (divedata->output, parser, data, size, fingerprint, fsize);

View File

@ -24,11 +24,9 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_GETOPT_H #ifdef HAVE_GETOPT_H
#include <getopt.h> #include <getopt.h>
#endif #endif

View File

@ -24,10 +24,8 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif #include <stdio.h>
#ifdef HAVE_GETOPT_H #ifdef HAVE_GETOPT_H
#include <getopt.h> #include <getopt.h>
#endif #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); rc = hw_ostc_device_fwupdate (device, hexfile);
break; break;
case DC_FAMILY_HW_OSTC3: case DC_FAMILY_HW_OSTC3:
rc = hw_ostc3_device_fwupdate (device, hexfile, false); rc = hw_ostc3_device_fwupdate (device, hexfile);
break; break;
case DC_FAMILY_DIVESYSTEM_IDIVE: case DC_FAMILY_DIVESYSTEM_IDIVE:
rc = divesystem_idive_device_fwupdate (device, hexfile); rc = divesystem_idive_device_fwupdate (device, hexfile);

View File

@ -24,10 +24,8 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif #include <stdio.h>
#ifdef HAVE_GETOPT_H #ifdef HAVE_GETOPT_H
#include <getopt.h> #include <getopt.h>
#endif #endif

View File

@ -24,10 +24,8 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif #include <stdio.h>
#ifdef HAVE_GETOPT_H #ifdef HAVE_GETOPT_H
#include <getopt.h> #include <getopt.h>
#endif #endif

View File

@ -24,11 +24,9 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_GETOPT_H #ifdef HAVE_GETOPT_H
#include <getopt.h> #include <getopt.h>
#endif #endif
@ -54,17 +52,17 @@ parse (dc_buffer_t *buffer, dc_context_t *context, dc_descriptor_t *descriptor,
// Create the parser. // Create the parser.
message ("Creating the parser.\n"); 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) { if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error creating the parser."); ERROR ("Error creating the parser.");
goto cleanup; goto cleanup;
} }
// Set the clock. // Register the data.
message ("Setting the clock.\n"); message ("Registering the data.\n");
rc = dc_parser_set_clock (parser, devtime, systime); rc = dc_parser_set_data (parser, data, size);
if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error setting the clock."); ERROR ("Error registering the data.");
goto cleanup; goto cleanup;
} }

View File

@ -24,10 +24,8 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif #include <stdio.h>
#ifdef HAVE_GETOPT_H #ifdef HAVE_GETOPT_H
#include <getopt.h> #include <getopt.h>
#endif #endif

View File

@ -24,10 +24,8 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif #include <stdio.h>
#ifdef HAVE_GETOPT_H #ifdef HAVE_GETOPT_H
#include <getopt.h> #include <getopt.h>
#endif #endif
@ -160,7 +158,7 @@ dctool_scan_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t
// Show help message. // Show help message.
if (help) { if (help) {
dctool_command_showhelp (&dctool_scan); dctool_command_showhelp (&dctool_list);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -24,10 +24,8 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif #include <stdio.h>
#ifdef HAVE_GETOPT_H #ifdef HAVE_GETOPT_H
#include <getopt.h> #include <getopt.h>
#endif #endif

View File

@ -24,10 +24,8 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif #include <stdio.h>
#ifdef HAVE_GETOPT_H #ifdef HAVE_GETOPT_H
#include <getopt.h> #include <getopt.h>
#endif #endif

View File

@ -24,10 +24,8 @@
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif #include <stdio.h>
#ifdef HAVE_GETOPT_H #ifdef HAVE_GETOPT_H
#include <getopt.h> #include <getopt.h>
#endif #endif

View File

@ -90,7 +90,7 @@ convert_volume (double value, dctool_units_t units)
} }
static void 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[] = { static const char *events[] = {
"none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter", "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; sample_data_t *sampledata = (sample_data_t *) userdata;
unsigned int seconds = 0, milliseconds = 0;
switch (type) { switch (type) {
case DC_SAMPLE_TIME: case DC_SAMPLE_TIME:
seconds = value->time / 1000;
milliseconds = value->time % 1000;
if (sampledata->nsamples++) if (sampledata->nsamples++)
fprintf (sampledata->ostream, "</sample>\n"); fprintf (sampledata->ostream, "</sample>\n");
fprintf (sampledata->ostream, "<sample>\n"); fprintf (sampledata->ostream, "<sample>\n");
if (milliseconds) { fprintf (sampledata->ostream, " <time>%02u:%02u</time>\n", value.time / 60, value.time % 60);
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);
}
break; break;
case DC_SAMPLE_DEPTH: case DC_SAMPLE_DEPTH:
fprintf (sampledata->ostream, " <depth>%.2f</depth>\n", fprintf (sampledata->ostream, " <depth>%.2f</depth>\n",
convert_depth(value->depth, sampledata->units)); convert_depth(value.depth, sampledata->units));
break; break;
case DC_SAMPLE_PRESSURE: case DC_SAMPLE_PRESSURE:
fprintf (sampledata->ostream, " <pressure tank=\"%u\">%.2f</pressure>\n", fprintf (sampledata->ostream, " <pressure tank=\"%u\">%.2f</pressure>\n",
value->pressure.tank, value.pressure.tank,
convert_pressure(value->pressure.value, sampledata->units)); convert_pressure(value.pressure.value, sampledata->units));
break; break;
case DC_SAMPLE_TEMPERATURE: case DC_SAMPLE_TEMPERATURE:
fprintf (sampledata->ostream, " <temperature>%.2f</temperature>\n", fprintf (sampledata->ostream, " <temperature>%.2f</temperature>\n",
convert_temperature(value->temperature, sampledata->units)); convert_temperature(value.temperature, sampledata->units));
break; break;
case DC_SAMPLE_EVENT: 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", 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; break;
case DC_SAMPLE_RBT: case DC_SAMPLE_RBT:
fprintf (sampledata->ostream, " <rbt>%u</rbt>\n", value->rbt); fprintf (sampledata->ostream, " <rbt>%u</rbt>\n", value.rbt);
break; break;
case DC_SAMPLE_HEARTBEAT: case DC_SAMPLE_HEARTBEAT:
fprintf (sampledata->ostream, " <heartbeat>%u</heartbeat>\n", value->heartbeat); fprintf (sampledata->ostream, " <heartbeat>%u</heartbeat>\n", value.heartbeat);
break; break;
case DC_SAMPLE_BEARING: case DC_SAMPLE_BEARING:
fprintf (sampledata->ostream, " <bearing>%u</bearing>\n", value->bearing); fprintf (sampledata->ostream, " <bearing>%u</bearing>\n", value.bearing);
break; break;
case DC_SAMPLE_VENDOR: case DC_SAMPLE_VENDOR:
fprintf (sampledata->ostream, " <vendor type=\"%u\" size=\"%u\">", value->vendor.type, value->vendor.size); fprintf (sampledata->ostream, " <vendor type=\"%u\" size=\"%u\">", value.vendor.type, value.vendor.size);
for (unsigned int i = 0; i < value->vendor.size; ++i) for (unsigned int i = 0; i < value.vendor.size; ++i)
fprintf (sampledata->ostream, "%02X", ((const unsigned char *) value->vendor.data)[i]); fprintf (sampledata->ostream, "%02X", ((const unsigned char *) value.vendor.data)[i]);
fprintf (sampledata->ostream, "</vendor>\n"); fprintf (sampledata->ostream, "</vendor>\n");
break; break;
case DC_SAMPLE_SETPOINT: case DC_SAMPLE_SETPOINT:
fprintf (sampledata->ostream, " <setpoint>%.2f</setpoint>\n", value->setpoint); fprintf (sampledata->ostream, " <setpoint>%.2f</setpoint>\n", value.setpoint);
break; break;
case DC_SAMPLE_PPO2: case DC_SAMPLE_PPO2:
if (value->ppo2.sensor != DC_SENSOR_NONE) { fprintf (sampledata->ostream, " <ppo2>%.2f</ppo2>\n", value.ppo2);
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);
}
break; break;
case DC_SAMPLE_CNS: 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; break;
case DC_SAMPLE_DECO: case DC_SAMPLE_DECO:
fprintf (sampledata->ostream, " <deco time=\"%u\" depth=\"%.2f\">%s</deco>\n", fprintf (sampledata->ostream, " <deco time=\"%u\" depth=\"%.2f\">%s</deco>\n",
value->deco.time, value.deco.time,
convert_depth(value->deco.depth, sampledata->units), convert_depth(value.deco.depth, sampledata->units),
decostop[value->deco.type]); decostop[value.deco.type]);
if (value->deco.tts) {
fprintf (sampledata->ostream, " <tts>%u</tts>\n",
value->deco.tts);
}
break; break;
case DC_SAMPLE_GASMIX: case DC_SAMPLE_GASMIX:
fprintf (sampledata->ostream, " <gasmix>%u</gasmix>\n", value->gasmix); fprintf (sampledata->ostream, " <gasmix>%u</gasmix>\n", value.gasmix);
break; break;
default: default:
break; 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", fprintf (output->ostream, "<datetime>%04i-%02i-%02i %02i:%02i:%02i %+03i:%02i</datetime>\n",
dt.year, dt.month, dt.day, dt.year, dt.month, dt.day,
dt.hour, dt.minute, dt.second, dt.hour, dt.minute, dt.second,
dt.timezone / 3600, (abs(dt.timezone) % 3600) / 60); dt.timezone / 3600, (dt.timezone % 3600) / 60);
} }
// Parse the divetime. // Parse the divetime.
@ -338,19 +322,11 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
"<gasmix>\n" "<gasmix>\n"
" <he>%.1f</he>\n" " <he>%.1f</he>\n"
" <o2>%.1f</o2>\n" " <o2>%.1f</o2>\n"
" <n2>%.1f</n2>\n", " <n2>%.1f</n2>\n"
"</gasmix>\n",
gasmix.helium * 100.0, gasmix.helium * 100.0,
gasmix.oxygen * 100.0, gasmix.oxygen * 100.0,
gasmix.nitrogen * 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. // 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", " <gasmix>%u</gasmix>\n",
tank.gasmix); 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) { if (tank.type != DC_TANKVOLUME_NONE) {
fprintf (output->ostream, fprintf (output->ostream,
" <type>%s</type>\n" " <type>%s</type>\n"
@ -416,30 +386,6 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
names[divemode]); 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. // Parse the salinity.
message ("Parsing the salinity.\n"); message ("Parsing the salinity.\n");
dc_salinity_t salinity = {DC_WATER_FRESH, 0.0}; 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) { if (status != DC_STATUS_UNSUPPORTED) {
const char *names[] = {"fresh", "salt"}; fprintf (output->ostream, "<salinity type=\"%u\">%.1f</salinity>\n",
if (salinity.density) { salinity.type, 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]);
}
} }
// Parse the atmospheric pressure. // Parse the atmospheric pressure.

View File

@ -26,12 +26,6 @@
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
#ifdef _MSC_VER
#define snprintf _snprintf
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#endif
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
#define FUNCTION __func__ #define FUNCTION __func__
#else #else

View File

@ -36,6 +36,9 @@ atomics_cobalt_device_version (dc_device_t *device, unsigned char data[], unsign
dc_status_t dc_status_t
atomics_cobalt_device_set_simulation (dc_device_t *device, unsigned int simulation); 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 #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -33,21 +33,6 @@ extern "C" {
*/ */
#define DC_IOCTL_BLE_GET_NAME DC_IOCTL_IOR('b', 0, DC_IOCTL_SIZE_VARIABLE) #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 #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -78,7 +78,6 @@ typedef enum dc_family_t {
DC_FAMILY_OCEANIC_VTPRO = (4 << 16), DC_FAMILY_OCEANIC_VTPRO = (4 << 16),
DC_FAMILY_OCEANIC_VEO250, DC_FAMILY_OCEANIC_VEO250,
DC_FAMILY_OCEANIC_ATOM2, DC_FAMILY_OCEANIC_ATOM2,
DC_FAMILY_PELAGIC_I330R,
/* Mares */ /* Mares */
DC_FAMILY_MARES_NEMO = (5 << 16), DC_FAMILY_MARES_NEMO = (5 << 16),
DC_FAMILY_MARES_PUCK, DC_FAMILY_MARES_PUCK,
@ -115,20 +114,14 @@ typedef enum dc_family_t {
DC_FAMILY_LIQUIVISION_LYNX = (17 << 16), DC_FAMILY_LIQUIVISION_LYNX = (17 << 16),
/* Sporasub */ /* Sporasub */
DC_FAMILY_SPORASUB_SP2 = (18 << 16), 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 // Not merged upstream yet
/* Garmin */ /* Garmin */
DC_FAMILY_GARMIN = (100 << 16), DC_FAMILY_GARMIN = (100 << 16),
/* Deepblu */
DC_FAMILY_DEEPBLU = (101 << 16),
/* Oceans S1 */
DC_FAMILY_OCEANS_S1 = (102 << 16),
} dc_family_t; } dc_family_t;
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -29,96 +29,29 @@
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
/**
* Opaque object representing a supported dive computer.
*/
typedef struct dc_descriptor_t dc_descriptor_t; 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_status_t
dc_descriptor_iterator (dc_iterator_t **iterator); dc_descriptor_iterator (dc_iterator_t **iterator);
/**
* Free the device descriptor.
*
* @param[in] descriptor A valid device descriptor.
*/
void void
dc_descriptor_free (dc_descriptor_t *descriptor); 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 * const char *
dc_descriptor_get_vendor (dc_descriptor_t *descriptor); 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 * const char *
dc_descriptor_get_product (dc_descriptor_t *descriptor); 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_family_t
dc_descriptor_get_type (dc_descriptor_t *descriptor); 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 unsigned int
dc_descriptor_get_model (dc_descriptor_t *descriptor); 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 unsigned int
dc_descriptor_get_transports (dc_descriptor_t *descriptor); 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 #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -22,8 +22,6 @@
#ifndef DC_HW_OSTC3_H #ifndef DC_HW_OSTC3_H
#define DC_HW_OSTC3_H #define DC_HW_OSTC3_H
#include <stdbool.h>
#include "common.h" #include "common.h"
#include "device.h" #include "device.h"
#include "datetime.h" #include "datetime.h"
@ -57,7 +55,7 @@ dc_status_t
hw_ostc3_device_config_reset (dc_device_t *abstract); hw_ostc3_device_config_reset (dc_device_t *abstract);
dc_status_t 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 #ifdef __cplusplus
} }

View File

@ -67,7 +67,6 @@ typedef enum dc_field_type_t {
DC_FIELD_TANK_COUNT, DC_FIELD_TANK_COUNT,
DC_FIELD_TANK, DC_FIELD_TANK,
DC_FIELD_DIVEMODE, DC_FIELD_DIVEMODE,
DC_FIELD_DECOMODEL,
DC_FIELD_STRING, DC_FIELD_STRING,
} dc_field_type_t; } dc_field_type_t;
@ -173,26 +172,19 @@ typedef struct dc_salinity_t {
double density; double density;
} dc_salinity_t; } 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 { typedef struct dc_gasmix_t {
double helium; double helium;
double oxygen; double oxygen;
double nitrogen; double nitrogen;
dc_usage_t usage;
} dc_gasmix_t; } dc_gasmix_t;
#define DC_SENSOR_NONE 0xFFFFFFFF
#define DC_GASMIX_UNKNOWN 0xFFFFFFFF #define DC_GASMIX_UNKNOWN 0xFFFFFFFF
typedef unsigned int dc_tankinfo_t; typedef unsigned int dc_tankinfo_t;
#define DC_TANKINFO_METRIC 1 #define DC_TANKINFO_METRIC 1
#define DC_TANKINFO_IMPERIAL 2 #define DC_TANKINFO_IMPERIAL 2
#define DC_TANKINFO_CC_DILUENT 4
#define DC_TANKINFO_CC_O2 8
// For backwards compatibility // For backwards compatibility
#define DC_TANKVOLUME_NONE 0 #define DC_TANKVOLUME_NONE 0
@ -222,11 +214,6 @@ typedef unsigned int dc_tankinfo_t;
* divide by 1 ATM (Vair = Vwater * Pwork / Patm). * 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 { typedef struct dc_tank_t {
unsigned int gasmix; /* Gas mix index, or DC_GASMIX_UNKNOWN */ unsigned int gasmix; /* Gas mix index, or DC_GASMIX_UNKNOWN */
dc_tankinfo_t type; /* Tank type - metric/imperial and oc/cc */ 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 workpressure; /* Work pressure (bar) */
double beginpressure; /* Begin pressure (bar) */ double beginpressure; /* Begin pressure (bar) */
double endpressure; /* End pressure (bar) */ double endpressure; /* End pressure (bar) */
dc_tank_usage_t usage;
} dc_tank_t; } 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 { typedef struct dc_field_string_t {
const char *desc; const char *desc;
const char *value; const char *value;
} dc_field_string_t; } dc_field_string_t;
typedef union dc_sample_value_t { typedef union dc_sample_value_t {
unsigned int time; /* Milliseconds */ unsigned int time;
double depth; double depth;
struct { struct {
unsigned int tank; unsigned int tank;
@ -303,41 +252,31 @@ typedef union dc_sample_value_t {
const void *data; const void *data;
} vendor; } vendor;
double setpoint; double setpoint;
struct { double ppo2;
unsigned int sensor;
double value;
} ppo2;
double cns; double cns;
struct { struct {
unsigned int type; unsigned int type;
unsigned int time; unsigned int time;
double depth; double depth;
unsigned int tts;
} deco; } deco;
unsigned int gasmix; /* Gas mix index */ unsigned int gasmix; /* Gas mix index */
} dc_sample_value_t; } dc_sample_value_t;
typedef struct dc_parser_t dc_parser_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_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_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_family_t
dc_parser_get_type (dc_parser_t *parser); dc_parser_get_type (dc_parser_t *parser);
dc_status_t dc_status_t
dc_parser_set_clock (dc_parser_t *parser, unsigned int devtime, dc_ticks_t systime); dc_parser_set_data (dc_parser_t *parser, const unsigned char *data, unsigned int size);
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_status_t dc_status_t
dc_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime); dc_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime);

View File

@ -35,6 +35,9 @@ extern "C" {
dc_status_t dc_status_t
reefnet_sensus_device_get_handshake (dc_device_t *device, unsigned char data[], unsigned int size); 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 #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -38,6 +38,9 @@ reefnet_sensuspro_device_get_handshake (dc_device_t *device, unsigned char data[
dc_status_t dc_status_t
reefnet_sensuspro_device_write_interval (dc_device_t *device, unsigned char interval); 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 #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -56,6 +56,9 @@ reefnet_sensusultra_device_write_parameter (dc_device_t *device, reefnet_sensusu
dc_status_t dc_status_t
reefnet_sensusultra_device_sense (dc_device_t *device, unsigned char data[], unsigned int size); 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 #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -86,14 +86,6 @@ typedef enum dc_usb_recipient_t {
DC_USB_RECIPIENT_OTHER = 0x03, DC_USB_RECIPIENT_OTHER = 0x03,
} dc_usb_recipient_t; } 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. * Opaque object representing a USB device.
*/ */

View File

@ -32,14 +32,6 @@
extern "C" { extern "C" {
#endif /* __cplusplus */ #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. * Opaque object representing a USB HID device.
*/ */

1011
msvc/libdivecomputer.vcproj Normal file

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@ endif
libdivecomputer_la_SOURCES = \ libdivecomputer_la_SOURCES = \
version.c \ version.c \
descriptor.c \ descriptor-private.h descriptor.c \
iostream-private.h iostream.c \ iostream-private.h iostream.c \
iterator-private.h iterator.c \ iterator-private.h iterator.c \
common-private.h common.c \ common-private.h common.c \
@ -43,7 +43,6 @@ libdivecomputer_la_SOURCES = \
oceanic_atom2.h oceanic_atom2.c oceanic_atom2_parser.c \ oceanic_atom2.h oceanic_atom2.c oceanic_atom2_parser.c \
oceanic_veo250.h oceanic_veo250.c oceanic_veo250_parser.c \ oceanic_veo250.h oceanic_veo250.c oceanic_veo250_parser.c \
oceanic_vtpro.h oceanic_vtpro.c oceanic_vtpro_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_common.h mares_common.c \
mares_nemo.h mares_nemo.c mares_nemo_parser.c \ mares_nemo.h mares_nemo.c mares_nemo_parser.c \
mares_puck.h mares_puck.c \ mares_puck.h mares_puck.c \
@ -76,14 +75,6 @@ libdivecomputer_la_SOURCES = \
mclean_extreme.h mclean_extreme.c mclean_extreme_parser.c \ mclean_extreme.h mclean_extreme.c mclean_extreme_parser.c \
liquivision_lynx.h liquivision_lynx.c liquivision_lynx_parser.c \ liquivision_lynx.h liquivision_lynx.c liquivision_lynx_parser.c \
sporasub_sp2.h sporasub_sp2.c sporasub_sp2_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 \ socket.h socket.c \
irda.c \ irda.c \
usb.c \ usb.c \
@ -95,7 +86,9 @@ libdivecomputer_la_SOURCES = \
libdivecomputer_la_SOURCES += \ libdivecomputer_la_SOURCES += \
usb_storage.c \ usb_storage.c \
field-cache.h field-cache.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 if OS_WIN32
libdivecomputer_la_SOURCES += serial_win32.c libdivecomputer_la_SOURCES += serial_win32.c
@ -113,7 +106,7 @@ libdivecomputer.exp: libdivecomputer.symbols
$(AM_V_GEN) sed -e '/^$$/d' $< > $@ $(AM_V_GEN) sed -e '/^$$/d' $< > $@
.rc.lo: .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 libdivecomputer.lo: revision.h

View File

@ -160,30 +160,6 @@ array_convert_str2num (const unsigned char data[], unsigned int size)
return value; 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 unsigned int
array_uint_be (const unsigned char data[], unsigned int n) 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; 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 unsigned int
array_uint32_be (const unsigned char data[]) array_uint32_be (const unsigned char data[])
{ {
@ -263,6 +213,17 @@ array_uint32_word_be (const unsigned char data[])
((unsigned int) data[3] << 16); ((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 unsigned int
array_uint24_be (const unsigned char data[]) array_uint24_be (const unsigned char data[])
{ {
@ -271,6 +232,16 @@ array_uint24_be (const unsigned char data[])
((unsigned int) data[2] << 0); ((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 unsigned int
array_uint24_le (const unsigned char data[]) array_uint24_le (const unsigned char data[])
{ {
@ -294,124 +265,8 @@ array_uint16_le (const unsigned char data[])
((unsigned int) data[1] << 8); ((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 unsigned char
bcd2dec (unsigned char value) bcd2dec (unsigned char value)
{ {
return ((value >> 4) & 0x0f) * 10 + (value & 0x0f); 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;
}

View File

@ -22,8 +22,6 @@
#ifndef ARRAY_H #ifndef ARRAY_H
#define ARRAY_H #define ARRAY_H
#define C_ARRAY_SIZE(a) (sizeof (a) / sizeof *(a))
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
@ -54,24 +52,12 @@ array_convert_hex2bin (const unsigned char input[], unsigned int isize, unsigned
unsigned int unsigned int
array_convert_str2num (const unsigned char data[], unsigned int size); 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 unsigned int
array_uint_be (const unsigned char data[], unsigned int n); array_uint_be (const unsigned char data[], unsigned int n);
unsigned int unsigned int
array_uint_le (const unsigned char data[], unsigned int n); 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 unsigned int
array_uint32_be (const unsigned char data[]); array_uint32_be (const unsigned char data[]);
@ -81,9 +67,15 @@ array_uint32_le (const unsigned char data[]);
unsigned int unsigned int
array_uint32_word_be (const unsigned char data[]); array_uint32_word_be (const unsigned char data[]);
void
array_uint32_le_set (unsigned char data[], const unsigned int input);
unsigned int unsigned int
array_uint24_be (const unsigned char data[]); array_uint24_be (const unsigned char data[]);
void
array_uint24_be_set (unsigned char data[], const unsigned int input);
unsigned int unsigned int
array_uint24_le (const unsigned char data[]); array_uint24_le (const unsigned char data[]);
@ -93,42 +85,9 @@ array_uint16_be (const unsigned char data[]);
unsigned short unsigned short
array_uint16_le (const unsigned char data[]); 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 unsigned char
bcd2dec (unsigned char value); 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 #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -41,8 +41,6 @@
#define FP_OFFSET 20 #define FP_OFFSET 20
#define SZ_HEADER 228
#define SZ_MEMORY1 (29 * 64 * 1024) // Cobalt 1 #define SZ_MEMORY1 (29 * 64 * 1024) // Cobalt 1
#define SZ_MEMORY2 (41 * 64 * 1024) // Cobalt 2 #define SZ_MEMORY2 (41 * 64 * 1024) // Cobalt 2
#define SZ_VERSION 14 #define SZ_VERSION 14
@ -349,12 +347,6 @@ atomics_cobalt_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
return DC_STATUS_SUCCESS; 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) { if (memcmp (data + FP_OFFSET, device->fingerprint, sizeof (device->fingerprint)) == 0) {
dc_buffer_free (buffer); dc_buffer_free (buffer);
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;

View File

@ -36,7 +36,7 @@ dc_status_t
atomics_cobalt_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); atomics_cobalt_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t 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 #ifdef __cplusplus
} }

View File

@ -46,10 +46,11 @@ typedef struct atomics_cobalt_parser_t atomics_cobalt_parser_t;
struct atomics_cobalt_parser_t { struct atomics_cobalt_parser_t {
dc_parser_t base; dc_parser_t base;
// Depth calibration. // Depth calibration.
double atmospheric;
double hydrostatic; 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_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_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static dc_status_t atomics_cobalt_parser_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 = { static const dc_parser_vtable_t atomics_cobalt_parser_vtable = {
sizeof(atomics_cobalt_parser_t), sizeof(atomics_cobalt_parser_t),
DC_FAMILY_ATOMICS_COBALT, DC_FAMILY_ATOMICS_COBALT,
NULL, /* set_clock */ atomics_cobalt_parser_set_data, /* set_data */
NULL, /* set_atmospheric */
atomics_cobalt_parser_set_density, /* set_density */
atomics_cobalt_parser_get_datetime, /* datetime */ atomics_cobalt_parser_get_datetime, /* datetime */
atomics_cobalt_parser_get_field, /* fields */ atomics_cobalt_parser_get_field, /* fields */
atomics_cobalt_parser_samples_foreach, /* samples_foreach */ atomics_cobalt_parser_samples_foreach, /* samples_foreach */
@ -68,7 +67,7 @@ static const dc_parser_vtable_t atomics_cobalt_parser_vtable = {
dc_status_t 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; 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; return DC_STATUS_INVALIDARGS;
// Allocate memory. // 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) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
} }
// Set the default values. // Set the default values.
parser->hydrostatic = DEF_DENSITY_SALT * GRAVITY; parser->atmospheric = 0.0;
parser->hydrostatic = 1025.0 * GRAVITY;
*out = (dc_parser_t*) parser; *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 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; 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_gasmix_t *gasmix = (dc_gasmix_t *) value;
dc_tank_t *tank = (dc_tank_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]; char buf[BUFLEN];
dc_field_string_t *string = (dc_field_string_t *) value; 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; unsigned int workpressure = 0;
if (value) { 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; *((unsigned int *) value) = array_uint16_le (p + 0x58) * 60;
break; break;
case DC_FIELD_MAXDEPTH: 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; break;
case DC_FIELD_GASMIX_COUNT: case DC_FIELD_GASMIX_COUNT:
case DC_FIELD_TANK_COUNT: case DC_FIELD_TANK_COUNT:
*((unsigned int *) value) = p[0x2a]; *((unsigned int *) value) = p[0x2a];
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = p[SZ_HEADER + SZ_GASMIX * flags + 5] / 100.0; gasmix->helium = p[SZ_HEADER + SZ_GASMIX * flags + 5] / 100.0;
gasmix->oxygen = p[SZ_HEADER + SZ_GASMIX * flags + 4] / 100.0; gasmix->oxygen = p[SZ_HEADER + SZ_GASMIX * flags + 4] / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; 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->gasmix = flags;
tank->beginpressure = array_uint16_le(p + 6) * PSI / BAR; tank->beginpressure = array_uint16_le(p + 6) * PSI / BAR;
tank->endpressure = array_uint16_le(p + 14) * PSI / BAR; tank->endpressure = array_uint16_le(p + 14) * PSI / BAR;
tank->usage = DC_TANK_USAGE_NONE;
break; break;
case DC_FIELD_DIVEMODE: case DC_FIELD_DIVEMODE:
switch(p[0x24]) { 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; return DC_STATUS_DATAFORMAT;
} }
break; break;
case DC_FIELD_ATMOSPHERIC:
*((double *) value) = atmospheric / 1000.0;
break;
case DC_FIELD_STRING: case DC_FIELD_STRING:
switch(flags) { switch(flags) {
case 0: // Serialnr 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) if (size < header + SZ_SEGMENT * nsegments)
return DC_STATUS_DATAFORMAT; 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 // Previous gas mix - initialize with impossible value
unsigned int gasmix_previous = 0xFFFFFFFF; unsigned int gasmix_previous = 0xFFFFFFFF;
@ -289,19 +304,19 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
// Time (seconds). // Time (seconds).
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/1000 bar). // Depth (1/1000 bar).
unsigned int depth = array_uint16_le (data + offset + 0); unsigned int depth = array_uint16_le (data + offset + 0);
sample.depth = (signed int)(depth - atmospheric) * (BAR / 1000.0) / parser->hydrostatic; sample.depth = (depth * BAR / 1000.0 - atmospheric) / parser->hydrostatic;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Pressure (1 psi). // Pressure (1 psi).
unsigned int pressure = array_uint16_le (data + offset + 2); unsigned int pressure = array_uint16_le (data + offset + 2);
sample.pressure.tank = tank; sample.pressure.tank = tank;
sample.pressure.value = pressure * PSI / BAR; 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 // Current gas mix
unsigned int gasmix = data[offset + 4]; 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; return DC_STATUS_DATAFORMAT;
} }
sample.gasmix = idx; sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix_previous = gasmix; gasmix_previous = gasmix;
} }
// Temperature (1 °F). // Temperature (1 °F).
unsigned int temperature = data[offset + 8]; unsigned int temperature = data[offset + 8];
sample.temperature = (temperature - 32.0) * (5.0 / 9.0); 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 // violation status
sample.event.type = 0; 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]; unsigned int violation = data[offset + 11];
if (violation & 0x01) { if (violation & 0x01) {
sample.event.type = SAMPLE_EVENT_ASCENT; 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) { if (violation & 0x04) {
sample.event.type = SAMPLE_EVENT_CEILING; 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) { if (violation & 0x08) {
sample.event.type = SAMPLE_EVENT_PO2; sample.event.type = SAMPLE_EVENT_PO2;
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
} }
// NDL & deco // 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.type = DC_DECO_NDL;
sample.deco.time = ndl; sample.deco.time = ndl;
sample.deco.depth = 0.0; 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; offset += SZ_SEGMENT;
} }

View File

@ -24,6 +24,7 @@
#endif #endif
#include <stdlib.h> // malloc, free #include <stdlib.h> // malloc, free
#include <stdio.h>
#include "socket.h" #include "socket.h"
@ -51,6 +52,7 @@
#include "context-private.h" #include "context-private.h"
#include "iostream-private.h" #include "iostream-private.h"
#include "iterator-private.h" #include "iterator-private.h"
#include "descriptor-private.h"
#include "platform.h" #include "platform.h"
#ifdef _WIN32 #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) if (str == NULL || size < DC_BLUETOOTH_SIZE)
return NULL; 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 >> 40) & 0xFF),
(unsigned char)((address >> 32) & 0xFF), (unsigned char)((address >> 32) & 0xFF),
(unsigned char)((address >> 24) & 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", INFO (abstract->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s",
address, name ? name : ""); 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; continue;
} }

View File

@ -68,13 +68,8 @@ checksum_xor_uint8 (const unsigned char data[], unsigned int size, unsigned char
} }
/*
* Polynomial: 0x1021
* RefIn: False
* RefOut: False
*/
unsigned short 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[] = { static const unsigned short crc_ccitt_table[] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 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) for (unsigned int i = 0; i < size; ++i)
crc = (crc << 8) ^ crc_ccitt_table[(crc >> 8) ^ data[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 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[] = { static const unsigned int crc_table[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
@ -322,16 +158,8 @@ checksum_crc32r (const unsigned char data[], unsigned int size)
return crc ^ 0xffffffff; return crc ^ 0xffffffff;
} }
/*
* Polynomial: 0x04C11DB7
* Init: 0xffffffff
* XorOut: 0xffffffff
* RefIn: False
* RefOut: False
*/
unsigned int 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[] = { static const unsigned int crc_table[] = {
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,

View File

@ -39,23 +39,14 @@ unsigned char
checksum_xor_uint8 (const unsigned char data[], unsigned int size, unsigned char init); checksum_xor_uint8 (const unsigned char data[], unsigned int size, unsigned char init);
unsigned short 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);
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);
unsigned int unsigned int
checksum_crc32 (const unsigned char data[], unsigned int size); checksum_crc32 (const unsigned char data[], unsigned int size);
unsigned int
checksum_crc32b (const unsigned char data[], unsigned int size);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -31,8 +31,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &citizen_aqualand_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &citizen_aqualand_device_vtable)
#define SZ_HEADER 32
typedef struct citizen_aqualand_device_t { typedef struct citizen_aqualand_device_t {
dc_device_t base; dc_device_t base;
dc_iostream_t *iostream; 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 char *data = dc_buffer_get_data (buffer);
unsigned int size = dc_buffer_get_size (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) { if (callback && memcmp (data + 0x05, device->fingerprint, sizeof (device->fingerprint)) != 0) {
callback (data, size, data + 0x05, sizeof (device->fingerprint), userdata); callback (data, size, data + 0x05, sizeof (device->fingerprint), userdata);
} }

View File

@ -35,7 +35,7 @@ dc_status_t
citizen_aqualand_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); citizen_aqualand_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t 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 #ifdef __cplusplus
} }

View File

@ -36,6 +36,7 @@ typedef struct citizen_aqualand_parser_t {
dc_parser_t base; dc_parser_t base;
} citizen_aqualand_parser_t; } 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_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_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static dc_status_t citizen_aqualand_parser_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 = { static const dc_parser_vtable_t citizen_aqualand_parser_vtable = {
sizeof(citizen_aqualand_parser_t), sizeof(citizen_aqualand_parser_t),
DC_FAMILY_CITIZEN_AQUALAND, DC_FAMILY_CITIZEN_AQUALAND,
NULL, /* set_clock */ citizen_aqualand_parser_set_data, /* set_data */
NULL, /* set_atmospheric */
NULL, /* set_density */
citizen_aqualand_parser_get_datetime, /* datetime */ citizen_aqualand_parser_get_datetime, /* datetime */
citizen_aqualand_parser_get_field, /* fields */ citizen_aqualand_parser_get_field, /* fields */
citizen_aqualand_parser_samples_foreach, /* samples_foreach */ citizen_aqualand_parser_samples_foreach, /* samples_foreach */
@ -54,7 +53,7 @@ static const dc_parser_vtable_t citizen_aqualand_parser_vtable = {
dc_status_t 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; 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; return DC_STATUS_INVALIDARGS;
// Allocate memory. // 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) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; 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 static dc_status_t
citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) 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
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth // Depth
if (metric) if (metric)
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
else else
sample.depth = depth * FEET; sample.depth = depth * FEET;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Temperature // Temperature
if (time % 300 == 0) { 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; sample.temperature = temperature / 10.0;
else else
sample.temperature = (temperature - 32.0) * (5.0 / 9.0); 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);
} }
} }
} }

View File

@ -30,6 +30,8 @@
#include "ringbuffer.h" #include "ringbuffer.h"
#include "rbstream.h" #include "rbstream.h"
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
#define MAXRETRIES 2 #define MAXRETRIES 2
#define COCHRAN_MODEL_COMMANDER_TM 0 #define COCHRAN_MODEL_COMMANDER_TM 0

View File

@ -35,7 +35,7 @@ dc_status_t
cochran_commander_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); cochran_commander_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t 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 #ifdef __cplusplus
} }

View File

@ -29,6 +29,8 @@
#include "parser-private.h" #include "parser-private.h"
#include "array.h" #include "array.h"
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
#define COCHRAN_MODEL_COMMANDER_TM 0 #define COCHRAN_MODEL_COMMANDER_TM 0
#define COCHRAN_MODEL_COMMANDER_PRE21000 1 #define COCHRAN_MODEL_COMMANDER_PRE21000 1
#define COCHRAN_MODEL_COMMANDER_AIR_NITROX 2 #define COCHRAN_MODEL_COMMANDER_AIR_NITROX 2
@ -99,6 +101,7 @@ typedef struct cochran_commander_parser_t {
unsigned int nevents; unsigned int nevents;
} cochran_commander_parser_t ; } 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_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_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); 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 = { static const dc_parser_vtable_t cochran_commander_parser_vtable = {
sizeof(cochran_commander_parser_t), sizeof(cochran_commander_parser_t),
DC_FAMILY_COCHRAN_COMMANDER, DC_FAMILY_COCHRAN_COMMANDER,
NULL, /* set_clock */ cochran_commander_parser_set_data, /* set_data */
NULL, /* set_atmospheric */
NULL, /* set_density */
cochran_commander_parser_get_datetime, /* datetime */ cochran_commander_parser_get_datetime, /* datetime */
cochran_commander_parser_get_field, /* fields */ cochran_commander_parser_get_field, /* fields */
cochran_commander_parser_samples_foreach, /* samples_foreach */ 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.time = 0;
sample.event.value = 0; sample.event.value = 0;
sample.event.flags = event->flag; 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 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; cochran_commander_parser_t *parser = NULL;
dc_status_t status = DC_STATUS_SUCCESS; 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; return DC_STATUS_INVALIDARGS;
// Allocate memory. // 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) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; 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 static dc_status_t
cochran_commander_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) 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 // Gas percentages are decimal and encoded as
// highbyte = integer portion // highbyte = integer portion
// lowbyte = decimal portion, divide by 256 to get decimal value // 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; gasmix->oxygen = array_uint16_le (data + layout->oxygen + 2 * flags) / 256.0 / 100;
if (layout->helium == UNSUPPORTED) { if (layout->helium == UNSUPPORTED) {
gasmix->helium = 0; 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 temp = samples[0]; // Half degrees F
unsigned int depth = samples[1]; // Half feet unsigned int depth = samples[1]; // Half feet
last_sample_time = sample.time = time * 1000; last_sample_time = sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
sample.depth = (depth / 2.0) * FEET; 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; 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; sample.gasmix = 0;
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
while (offset < size) { while (offset < size) {
const unsigned char *s = samples + offset; const unsigned char *s = samples + offset;
sample.time = time * 1000; sample.time = time;
if (last_sample_time != sample.time) { if (last_sample_time != sample.time) {
// We haven't issued this time yet. // We haven't issued this time yet.
last_sample_time = sample.time; last_sample_time = sample.time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
} }
if (*s & 0x80) { 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.type = DC_DECO_DECOSTOP;
sample.deco.time = 60; // We don't know the duration sample.deco.time = 60; // We don't know the duration
sample.deco.depth = deco_ceiling * FEET; 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; break;
case 0xAD: // Increment ceiling (shallower) case 0xAD: // Increment ceiling (shallower)
deco_ceiling -= 10; // feet 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.type = DC_DECO_DECOSTOP;
sample.deco.depth = deco_ceiling * FEET; sample.deco.depth = deco_ceiling * FEET;
sample.deco.time = 60; // We don't know the duration 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; break;
default: default:
cochran_commander_handle_event(parser, s[0], callback, userdata); 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 else
temp += (*s & 0x0f); temp += (*s & 0x0f);
sample.temperature = (temp / 2.0 - 32.0) / 1.8; 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++; offset++;
@ -644,7 +649,7 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
depth += s[0] & 0x3f; depth += s[0] & 0x3f;
sample.depth = (depth / 2.0) * FEET; sample.depth = (depth / 2.0) * FEET;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
offset++; offset++;
time += sample_interval; 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; start_depth = array_uint16_le (data + layout->start_depth) / 256.0;
} }
last_sample_time = sample.time = time * 1000; last_sample_time = sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
sample.depth = start_depth * FEET; 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; 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; 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; unsigned int last_gasmix = sample.gasmix;
while (offset < size) { while (offset < size) {
const unsigned char *s = samples + offset; const unsigned char *s = samples + offset;
sample.time = time * 1000; sample.time = time;
if (last_sample_time != sample.time) { if (last_sample_time != sample.time) {
// We haven't issued this time yet. // We haven't issued this time yet.
last_sample_time = sample.time; 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 // 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.type = DC_DECO_DECOSTOP;
sample.deco.time = (array_uint16_le(s + 3) + 1) * 60; sample.deco.time = (array_uint16_le(s + 3) + 1) * 60;
sample.deco.depth = deco_ceiling * FEET; 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; break;
case 0xAD: // Increment ceiling (shallower) case 0xAD: // Increment ceiling (shallower)
deco_ceiling -= 10; // feet 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.type = DC_DECO_DECOSTOP;
sample.deco.depth = deco_ceiling * FEET; sample.deco.depth = deco_ceiling * FEET;
sample.deco.time = (array_uint16_le(s + 3) + 1) * 60; 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; break;
case 0xC0: // Switched to FO2 21% mode (surface) case 0xC0: // Switched to FO2 21% mode (surface)
// Event seen upon surfacing // 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 case 0xEF: // Switched to gas blend 2
if (last_gasmix != 1) { if (last_gasmix != 1) {
sample.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; last_gasmix = sample.gasmix;
} }
break; break;
case 0xF3: // Switched to gas blend 1 case 0xF3: // Switched to gas blend 1
if (last_gasmix != 0) { if (last_gasmix != 0) {
sample.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; last_gasmix = sample.gasmix;
} }
break; break;
@ -814,7 +817,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
depth += (s[0] & 0x3f); depth += (s[0] & 0x3f);
sample.depth = (start_depth + depth / 4.0) * FEET; 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. // Ascent rate is logged in the 0th sample, temp in the 1st, repeat.
if (time % 2 == 0) { 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; double temperature = s[1] / 2.0 + 20.0;
sample.temperature = (temperature - 32.0) / 1.8; 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 // 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.type = DC_DECO_NDL;
sample.deco.time = deco_time * 60; sample.deco.time = deco_time * 60;
sample.deco.depth = 0; 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; break;
case 23: 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.type = DC_DECO_DECOSTOP;
sample.deco.depth = deco_ceiling * FEET; sample.deco.depth = deco_ceiling * FEET;
sample.deco.time = deco_time * 60; 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; break;
} }

View File

@ -28,8 +28,6 @@
#include <libdivecomputer/context.h> #include <libdivecomputer/context.h>
#include "platform.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
@ -42,6 +40,12 @@ extern "C" {
#define FUNCTION __FUNCTION__ #define FUNCTION __FUNCTION__
#endif #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 #ifdef ENABLE_LOGGING
#define HEXDUMP(context, loglevel, prefix, data, size) dc_context_hexdump (context, loglevel, __FILE__, __LINE__, FUNCTION, prefix, data, size) #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) #define SYSERROR(context, errcode) dc_context_syserror (context, DC_LOGLEVEL_ERROR, __FILE__, __LINE__, FUNCTION, errcode)
@ -59,7 +63,7 @@ extern "C" {
#endif #endif
dc_status_t 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_status_t
dc_context_syserror (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, int errcode); dc_context_syserror (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, int errcode);

View File

@ -25,6 +25,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h>
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
@ -35,7 +36,6 @@
#endif #endif
#include "context-private.h" #include "context-private.h"
#include "platform.h"
#include "timer.h" #include "timer.h"
struct dc_context_t { struct dc_context_t {
@ -49,6 +49,55 @@ struct dc_context_t {
}; };
#ifdef ENABLE_LOGGING #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 >= 0 && (size_t) 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 static int
l_hexdump (char *str, size_t size, const unsigned char data[], size_t n) l_hexdump (char *str, size_t size, const unsigned char data[], size_t n)
{ {
@ -195,7 +244,7 @@ dc_context_log (dc_context_t *context, dc_loglevel_t loglevel, const char *file,
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
va_start (ap, format); 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); va_end (ap);
context->logfunc (context, loglevel, file, line, function, context->msg, context->userdata); context->logfunc (context, loglevel, file, line, function, context->msg, context->userdata);
@ -261,7 +310,7 @@ dc_context_hexdump (dc_context_t *context, dc_loglevel_t loglevel, const char *f
if (context->logfunc == NULL) if (context->logfunc == NULL)
return DC_STATUS_SUCCESS; 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) { if (n >= 0) {
n = l_hexdump (context->msg + n, sizeof (context->msg) - n, data, size); n = l_hexdump (context->msg + n, sizeof (context->msg) - n, data, size);

View File

@ -38,8 +38,6 @@
#define SZ_PACKET 0x80 #define SZ_PACKET 0x80
#define SZ_PAGE (SZ_PACKET / 4) #define SZ_PAGE (SZ_PACKET / 4)
#define SZ_HEADER 32
#define IQ700 0x05 #define IQ700 0x05
#define EDY 0x08 #define EDY 0x08
@ -381,14 +379,7 @@ cressi_edy_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
} }
// Emit a device info event. return device_dump_read (abstract, dc_buffer_get_data (buffer),
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),
dc_buffer_get_size (buffer), SZ_PACKET); 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; 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; unsigned char *p = buffer + offset;
if (memcmp (p, device->fingerprint, sizeof (device->fingerprint)) == 0) if (memcmp (p, device->fingerprint, sizeof (device->fingerprint)) == 0)

View File

@ -35,7 +35,7 @@ dc_status_t
cressi_edy_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); cressi_edy_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t 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 #ifdef __cplusplus
} }

View File

@ -31,8 +31,6 @@
#define IQ700 0x05 #define IQ700 0x05
#define EDY 0x08 #define EDY 0x08
#define SZ_HEADER 32
typedef struct cressi_edy_parser_t cressi_edy_parser_t; typedef struct cressi_edy_parser_t cressi_edy_parser_t;
struct cressi_edy_parser_t { struct cressi_edy_parser_t {
@ -40,6 +38,7 @@ struct cressi_edy_parser_t {
unsigned int model; 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_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_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static dc_status_t cressi_edy_parser_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 = { static const dc_parser_vtable_t cressi_edy_parser_vtable = {
sizeof(cressi_edy_parser_t), sizeof(cressi_edy_parser_t),
DC_FAMILY_CRESSI_EDY, DC_FAMILY_CRESSI_EDY,
NULL, /* set_clock */ cressi_edy_parser_set_data, /* set_data */
NULL, /* set_atmospheric */
NULL, /* set_density */
cressi_edy_parser_get_datetime, /* datetime */ cressi_edy_parser_get_datetime, /* datetime */
cressi_edy_parser_get_field, /* fields */ cressi_edy_parser_get_field, /* fields */
cressi_edy_parser_samples_foreach, /* samples_foreach */ cressi_edy_parser_samples_foreach, /* samples_foreach */
@ -73,7 +70,7 @@ cressi_edy_parser_count_gasmixes (const unsigned char *data)
} }
dc_status_t 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; 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; return DC_STATUS_INVALIDARGS;
// Allocate memory. // 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) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; 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 static dc_status_t
cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) 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; return DC_STATUS_DATAFORMAT;
const unsigned char *p = abstract->data; 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; cressi_edy_parser_t *parser = (cressi_edy_parser_t *) abstract;
if (abstract->size < SZ_HEADER) if (abstract->size < 32)
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
const unsigned char *p = abstract->data; 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); *((unsigned int *) value) = cressi_edy_parser_count_gasmixes(p);
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = 0.0; gasmix->helium = 0.0;
gasmix->oxygen = bcd2dec (p[0x17 - flags]) / 100.0; gasmix->oxygen = bcd2dec (p[0x17 - flags]) / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; 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 ngasmixes = cressi_edy_parser_count_gasmixes(data);
unsigned int gasmix = 0xFFFFFFFF; unsigned int gasmix = 0xFFFFFFFF;
unsigned int offset = SZ_HEADER; unsigned int offset = 32;
while (offset + 2 <= size) { while (offset + 2 <= size) {
dc_sample_value_t sample = {0}; 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 (seconds).
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/10 m). // Depth (1/10 m).
unsigned int depth = bcd2dec (data[offset + 0] & 0x0F) * 100 + bcd2dec (data[offset + 1]); unsigned int depth = bcd2dec (data[offset + 0] & 0x0F) * 100 + bcd2dec (data[offset + 1]);
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Current gasmix // Current gasmix
if (ngasmixes) { if (ngasmixes) {
@ -214,7 +217,7 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
} }
if (idx != gasmix) { if (idx != gasmix) {
sample.gasmix = idx; sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix = idx; gasmix = idx;
} }
} }

View File

@ -93,7 +93,7 @@ cressi_goa_device_send (cressi_goa_device_t *device, unsigned char cmd, const un
if (size) { if (size) {
memcpy (packet + 5, data, 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 + 0] = (crc ) & 0xFF; // Low
packet[5 + size + 1] = (crc >> 8) & 0xFF; // High packet[5 + size + 1] = (crc >> 8) & 0xFF; // High
packet[5 + size + 2] = TRAILER; 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. // Verify the checksum of the packet.
unsigned short crc = array_uint16_le (packet + length + 5); 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) { if (crc != ccrc) {
ERROR (abstract->context, "Unexpected answer checksum."); ERROR (abstract->context, "Unexpected answer checksum.");
return DC_STATUS_PROTOCOL; 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. // Verify the checksum of the packet.
unsigned short crc = array_uint16_le (packet + sizeof(packet) - 2); 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) { if (crc != ccrc) {
ERROR (abstract->context, "Unexpected answer checksum."); ERROR (abstract->context, "Unexpected answer checksum.");
return DC_STATUS_PROTOCOL; return DC_STATUS_PROTOCOL;

View File

@ -35,7 +35,7 @@ dc_status_t
cressi_goa_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); cressi_goa_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t 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 #ifdef __cplusplus
} }

View File

@ -28,7 +28,12 @@
#define ISINSTANCE(parser) dc_device_isinstance((parser), &cressi_goa_parser_vtable) #define ISINSTANCE(parser) dc_device_isinstance((parser), &cressi_goa_parser_vtable)
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
#define SZ_HEADER 23 #define SZ_HEADER 23
#define SZ_HEADER_SCUBA 0x61
#define SZ_HEADER_FREEDIVE 0x2B
#define SZ_HEADER_GAUGE 0x2D
#define DEPTH 0 #define DEPTH 0
#define DEPTH2 1 #define DEPTH2 1
@ -40,28 +45,17 @@
#define FREEDIVE 2 #define FREEDIVE 2
#define GAUGE 3 #define GAUGE 3
#define NGASMIXES 2
#define UNDEFINED 0xFFFFFFFF
typedef struct cressi_goa_parser_t cressi_goa_parser_t; typedef struct cressi_goa_parser_t cressi_goa_parser_t;
struct cressi_goa_parser_t { struct cressi_goa_parser_t {
dc_parser_t base; dc_parser_t base;
unsigned int model; unsigned int model;
// Cached fields.
unsigned int cached;
double maxdepth;
}; };
typedef struct cressi_goa_layout_t { static dc_status_t cressi_goa_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
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_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); 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_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); static dc_status_t cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -69,64 +63,22 @@ static dc_status_t cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_
static const dc_parser_vtable_t cressi_goa_parser_vtable = { static const dc_parser_vtable_t cressi_goa_parser_vtable = {
sizeof(cressi_goa_parser_t), sizeof(cressi_goa_parser_t),
DC_FAMILY_CRESSI_GOA, DC_FAMILY_CRESSI_GOA,
NULL, /* set_clock */ cressi_goa_parser_set_data, /* set_data */
NULL, /* set_atmospheric */
NULL, /* set_density */
cressi_goa_parser_get_datetime, /* datetime */ cressi_goa_parser_get_datetime, /* datetime */
cressi_goa_parser_get_field, /* fields */ cressi_goa_parser_get_field, /* fields */
cressi_goa_parser_samples_foreach, /* samples_foreach */ cressi_goa_parser_samples_foreach, /* samples_foreach */
NULL /* destroy */ NULL /* destroy */
}; };
static const cressi_goa_layout_t layouts[] = { static const unsigned int headersizes[] = {
/* SCUBA */ SZ_HEADER_SCUBA,
{ SZ_HEADER_SCUBA,
0x61, /* headersize */ SZ_HEADER_FREEDIVE,
0x11, /* datetime */ SZ_HEADER_GAUGE,
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 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; cressi_goa_parser_t *parser = NULL;
@ -134,19 +86,33 @@ cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, const unsign
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // 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) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
} }
parser->model = model; parser->model = model;
parser->cached = 0;
parser->maxdepth = 0.0;
*out = (dc_parser_t*) parser; *out = (dc_parser_t*) parser;
return DC_STATUS_SUCCESS; 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 static dc_status_t
cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -157,16 +123,15 @@ cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
unsigned int divemode = data[2]; unsigned int divemode = data[2];
if (divemode >= C_ARRAY_SIZE(layouts)) { if (divemode >= C_ARRAY_SIZE(headersizes)) {
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
const cressi_goa_layout_t *layout = &layouts[divemode]; unsigned int headersize = headersizes[divemode];
if (size < headersize)
if (size < layout->headersize)
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
const unsigned char *p = abstract->data + layout->datetime; const unsigned char *p = abstract->data + 0x11;
if (datetime) { if (datetime) {
datetime->year = array_uint16_le(p); datetime->year = array_uint16_le(p);
@ -184,6 +149,7 @@ cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
static dc_status_t 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_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;
const unsigned char *data = abstract->data; const unsigned char *data = abstract->data;
unsigned int size = abstract->size; unsigned int size = abstract->size;
@ -191,22 +157,23 @@ cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
unsigned int divemode = data[2]; unsigned int divemode = data[2];
if (divemode >= C_ARRAY_SIZE(layouts)) { if (divemode >= C_ARRAY_SIZE(headersizes)) {
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
const cressi_goa_layout_t *layout = &layouts[divemode]; unsigned int headersize = headersizes[divemode];
if (size < headersize)
if (size < layout->headersize)
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
unsigned int ngasmixes = 0; if (!parser->cached) {
if (layout->gasmix != UNDEFINED) { sample_statistics_t statistics = SAMPLE_STATISTICS_INITIALIZER;
for (unsigned int i = 0; i < NGASMIXES; ++i) { dc_status_t rc = cressi_goa_parser_samples_foreach (
if (data[layout->gasmix + 2 * i + 1] == 0) abstract, sample_statistics_cb, &statistics);
break; if (rc != DC_STATUS_SUCCESS)
ngasmixes++; return rc;
}
parser->cached = 1;
parser->maxdepth = statistics.maxdepth;
} }
dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
@ -214,37 +181,17 @@ cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
if (value) { if (value) {
switch (type) { switch (type) {
case DC_FIELD_DIVETIME: case DC_FIELD_DIVETIME:
if (layout->divetime == UNDEFINED) *((unsigned int *) value) = array_uint16_le (data + 0x19);
return DC_STATUS_UNSUPPORTED;
*((unsigned int *) value) = array_uint16_le (data + layout->divetime);
break; break;
case DC_FIELD_MAXDEPTH: case DC_FIELD_MAXDEPTH:
if (layout->maxdepth == UNDEFINED) *((double *) value) = parser->maxdepth;
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;
break; break;
case DC_FIELD_GASMIX_COUNT: case DC_FIELD_GASMIX_COUNT:
*((unsigned int *) value) = ngasmixes; *((unsigned int *) value) = divemode == SCUBA || divemode == NITROX ? 2 : 0;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = 0.0; gasmix->helium = 0.0;
gasmix->oxygen = data[layout->gasmix + 2 * flags + 1] / 100.0; gasmix->oxygen = data[0x20 + 2 * flags] / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
break; break;
case DC_FIELD_DIVEMODE: case DC_FIELD_DIVEMODE:
@ -281,13 +228,12 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
unsigned int divemode = data[2]; unsigned int divemode = data[2];
if (divemode >= C_ARRAY_SIZE(layouts)) { if (divemode >= C_ARRAY_SIZE(headersizes)) {
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
const cressi_goa_layout_t *layout = &layouts[divemode]; unsigned int headersize = headersizes[divemode];
if (size < headersize)
if (size < layout->headersize)
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
unsigned int interval = divemode == FREEDIVE ? 2 : 5; unsigned int interval = divemode == FREEDIVE ? 2 : 5;
@ -299,7 +245,7 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
unsigned int have_temperature = 0; unsigned int have_temperature = 0;
unsigned int complete = 0; unsigned int complete = 0;
unsigned int offset = layout->headersize; unsigned int offset = headersize;
while (offset + 2 <= size) { while (offset + 2 <= size) {
dc_sample_value_t sample = {0}; dc_sample_value_t sample = {0};
@ -322,25 +268,25 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
if (complete) { if (complete) {
// Time (seconds). // Time (seconds).
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Temperature (1/10 °C). // Temperature (1/10 °C).
if (have_temperature) { if (have_temperature) {
sample.temperature = temperature / 10.0; sample.temperature = temperature / 10.0;
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
have_temperature = 0; have_temperature = 0;
} }
// Depth (1/10 m). // Depth (1/10 m).
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Gas change // Gas change
if (divemode == SCUBA || divemode == NITROX) { if (divemode == SCUBA || divemode == NITROX) {
if (gasmix != gasmix_previous) { if (gasmix != gasmix_previous) {
sample.gasmix = gasmix; sample.gasmix = gasmix;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix_previous = gasmix; gasmix_previous = gasmix;
} }
} }

View File

@ -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); array_convert_bin2hex (raw, rsize, ascii + 1, 2 * rsize);
// Checksum // 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[] = { unsigned char checksum[] = {
(crc >> 8) & 0xFF, // High (crc >> 8) & 0xFF, // High
(crc ) & 0xFF}; // Low (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. // Verify the checksum of the packet.
unsigned short crc = array_uint16_be (checksum); 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) { if (crc != ccrc) {
ERROR (abstract->context, "Unexpected answer checksum."); ERROR (abstract->context, "Unexpected answer checksum.");
return DC_STATUS_PROTOCOL; return DC_STATUS_PROTOCOL;
@ -372,19 +372,12 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
// Verify the checksum. // Verify the checksum.
unsigned int csum1 = array_uint16_be (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) { if (csum1 != csum2) {
ERROR (abstract->context, "Unexpected answer bytes."); ERROR (abstract->context, "Unexpected answer bytes.");
return DC_STATUS_PROTOCOL; 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; return DC_STATUS_SUCCESS;
} }
@ -401,6 +394,13 @@ cressi_leonardo_device_foreach (dc_device_t *abstract, dc_dive_callback_t callba
return rc; 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), rc = cressi_leonardo_extract_dives (abstract, dc_buffer_get_data (buffer),
dc_buffer_get_size (buffer), callback, userdata); dc_buffer_get_size (buffer), callback, userdata);

View File

@ -35,7 +35,7 @@ dc_status_t
cressi_leonardo_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); cressi_leonardo_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t 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 #ifdef __cplusplus
} }

View File

@ -39,6 +39,7 @@ struct cressi_leonardo_parser_t {
unsigned int model; 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_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_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static dc_status_t cressi_leonardo_parser_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 = { static const dc_parser_vtable_t cressi_leonardo_parser_vtable = {
sizeof(cressi_leonardo_parser_t), sizeof(cressi_leonardo_parser_t),
DC_FAMILY_CRESSI_LEONARDO, DC_FAMILY_CRESSI_LEONARDO,
NULL, /* set_clock */ cressi_leonardo_parser_set_data, /* set_data */
NULL, /* set_atmospheric */
NULL, /* set_density */
cressi_leonardo_parser_get_datetime, /* datetime */ cressi_leonardo_parser_get_datetime, /* datetime */
cressi_leonardo_parser_get_field, /* fields */ cressi_leonardo_parser_get_field, /* fields */
cressi_leonardo_parser_samples_foreach, /* samples_foreach */ cressi_leonardo_parser_samples_foreach, /* samples_foreach */
@ -57,7 +56,7 @@ static const dc_parser_vtable_t cressi_leonardo_parser_vtable = {
dc_status_t 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; 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; return DC_STATUS_INVALIDARGS;
// Allocate memory. // 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) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; 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 static dc_status_t
cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) 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; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = 0.0; gasmix->helium = 0.0;
gasmix->oxygen = data[0x19] / 100.0; gasmix->oxygen = data[0x19] / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; 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_previous = 0xFFFFFFFF;
unsigned int gasmix = 0; unsigned int gasmix = 0;
if (parser->model == DRAKE) {
gasmix = gasmix_previous;
}
unsigned int offset = SZ_HEADER; unsigned int offset = SZ_HEADER;
while (offset + 2 <= size) { while (offset + 2 <= size) {
@ -188,12 +190,12 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
// Time (seconds). // Time (seconds).
time += surftime; time += surftime;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/10 m). // Depth (1/10 m).
sample.depth = 0.0; sample.depth = 0.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
offset += 4; offset += 4;
} else { } else {
@ -203,17 +205,17 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
// Time (seconds). // Time (seconds).
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/10 m). // Depth (1/10 m).
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Gas change. // Gas change.
if (gasmix != gasmix_previous) { if (gasmix != gasmix_previous) {
sample.gasmix = gasmix; sample.gasmix = gasmix;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix_previous = gasmix; gasmix_previous = gasmix;
} }
@ -221,13 +223,9 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
if (ascent) { if (ascent) {
sample.event.type = SAMPLE_EVENT_ASCENT; sample.event.type = SAMPLE_EVENT_ASCENT;
sample.event.time = 0; sample.event.time = 0;
if (ascent < 3) sample.event.flags = 0;
// 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.value = ascent; sample.event.value = ascent;
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
} }
offset += 2; offset += 2;

500
src/deepblu.c Normal file
View 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;
}

View File

@ -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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -18,10 +18,9 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA * MA 02110-1301 USA
*/ */
// test 01
#ifndef PELAGIC_I330R_H #ifndef DEEPBLU_H
#define PELAGIC_I330R_H #define DEEPBLU_H
#include <libdivecomputer/context.h> #include <libdivecomputer/context.h>
#include <libdivecomputer/iostream.h> #include <libdivecomputer/iostream.h>
@ -33,9 +32,12 @@ extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
dc_status_t 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 #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif /* PELAGIC_I330R_H */ #endif /* DEEPBLU_H */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/* /*
* libdivecomputer * libdivecomputer
* *
* Copyright (C) 2022 Jef Driesen * Copyright (C) 2017 Jef Driesen
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -19,17 +19,33 @@
* MA 02110-1301 USA * MA 02110-1301 USA
*/ */
#ifndef OCEANS_S1_COMMON_H #ifndef DC_DESCRIPTOR_PRIVATE_H
#define OCEANS_S1_COMMON_H #define DC_DESCRIPTOR_PRIVATE_H
#include <libdivecomputer/descriptor.h>
// Oh joy. Windows is some truly horrendously broken crap
#undef interface
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #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 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 #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif /* OCEANS_S1_COMMON_H */ #endif /* DC_DESCRIPTOR_PRIVATE_H */

View File

@ -23,10 +23,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <libdivecomputer/descriptor.h> #include "descriptor-private.h"
#include <libdivecomputer/usbhid.h>
#include <libdivecomputer/usb.h>
#include "iterator-private.h" #include "iterator-private.h"
#include "platform.h" #include "platform.h"
@ -39,29 +36,37 @@
values, \ values, \
C_ARRAY_SIZE(values) - isnullterminated, \ C_ARRAY_SIZE(values) - isnullterminated, \
C_ARRAY_ITEMSIZE(values), \ 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_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_uwatec (dc_transport_t transport, const void *userdata, void *params);
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 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 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 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 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 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 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 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 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 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);
// Not merged upstream yet // 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); static dc_status_t dc_descriptor_iterator_next (dc_iterator_t *iterator, void *item);
@ -170,13 +175,9 @@ static const dc_descriptor_t g_descriptors[] = {
{"Scubapro", "Aladin A1", DC_FAMILY_UWATEC_SMART, 0x25, DC_TRANSPORT_BLE, dc_filter_uwatec}, {"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", "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", "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", 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", "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", "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 */
{"Reefnet", "Sensus", DC_FAMILY_REEFNET_SENSUS, 1, DC_TRANSPORT_SERIAL, NULL}, {"Reefnet", "Sensus", DC_FAMILY_REEFNET_SENSUS, 1, DC_TRANSPORT_SERIAL, NULL},
{"Reefnet", "Sensus Pro", DC_FAMILY_REEFNET_SENSUSPRO, 2, DC_TRANSPORT_SERIAL, NULL}, {"Reefnet", "Sensus Pro", DC_FAMILY_REEFNET_SENSUSPRO, 2, DC_TRANSPORT_SERIAL, NULL},
@ -255,7 +256,7 @@ static const dc_descriptor_t g_descriptors[] = {
{"Sherwood", "Vision", DC_FAMILY_OCEANIC_ATOM2, 0x4556, DC_TRANSPORT_SERIAL, NULL}, {"Sherwood", "Vision", DC_FAMILY_OCEANIC_ATOM2, 0x4556, DC_TRANSPORT_SERIAL, NULL},
{"Oceanic", "VTX", DC_FAMILY_OCEANIC_ATOM2, 0x4557, 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", "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 | DC_TRANSPORT_BLE, dc_filter_oceanic},
{"Aqualung", "i450T", DC_FAMILY_OCEANIC_ATOM2, 0x4641, DC_TRANSPORT_SERIAL, NULL}, {"Aqualung", "i450T", DC_FAMILY_OCEANIC_ATOM2, 0x4641, DC_TRANSPORT_SERIAL, NULL},
{"Aqualung", "i550", DC_FAMILY_OCEANIC_ATOM2, 0x4642, 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}, {"Aqualung", "i200", DC_FAMILY_OCEANIC_ATOM2, 0x4646, DC_TRANSPORT_SERIAL, NULL},
@ -269,15 +270,8 @@ 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}, {"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}, {"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}, {"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}, {"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", "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 */
{"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL}, {"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
{"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL}, {"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
@ -302,7 +296,6 @@ static const dc_descriptor_t g_descriptors[] = {
{"Mares", "Icon HD", DC_FAMILY_MARES_ICONHD , 0x14, DC_TRANSPORT_SERIAL, NULL}, {"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", "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", "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", "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", "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", "Puck 2", DC_FAMILY_MARES_ICONHD , 0x1F, DC_TRANSPORT_SERIAL, NULL},
@ -337,11 +330,8 @@ static const dc_descriptor_t g_descriptors[] = {
{"Cressi", "Newton", DC_FAMILY_CRESSI_LEONARDO, 5, DC_TRANSPORT_SERIAL, NULL}, {"Cressi", "Newton", DC_FAMILY_CRESSI_LEONARDO, 5, DC_TRANSPORT_SERIAL, NULL},
{"Cressi", "Drake", DC_FAMILY_CRESSI_LEONARDO, 6, DC_TRANSPORT_SERIAL, NULL}, {"Cressi", "Drake", DC_FAMILY_CRESSI_LEONARDO, 6, DC_TRANSPORT_SERIAL, NULL},
/* Cressi Goa */ /* Cressi Goa */
{"Cressi", "Cartesio", DC_FAMILY_CRESSI_GOA, 1, 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, NULL}, {"Cressi", "Goa", DC_FAMILY_CRESSI_GOA, 2, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, 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},
/* Zeagle N2iTiON3 */ /* Zeagle N2iTiON3 */
{"Zeagle", "N2iTiON3", DC_FAMILY_ZEAGLE_N2ITION3, 0, DC_TRANSPORT_SERIAL, NULL}, {"Zeagle", "N2iTiON3", DC_FAMILY_ZEAGLE_N2ITION3, 0, DC_TRANSPORT_SERIAL, NULL},
{"Apeks", "Quantum X", DC_FAMILY_ZEAGLE_N2ITION3, 0, DC_TRANSPORT_SERIAL, NULL}, {"Apeks", "Quantum X", DC_FAMILY_ZEAGLE_N2ITION3, 0, DC_TRANSPORT_SERIAL, NULL},
@ -361,9 +351,6 @@ static const dc_descriptor_t g_descriptors[] = {
{"Shearwater", "Nerd 2", DC_FAMILY_SHEARWATER_PETREL, 7, DC_TRANSPORT_BLE, dc_filter_shearwater}, {"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", "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", "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 */
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0, DC_TRANSPORT_SERIAL, NULL}, {"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0, DC_TRANSPORT_SERIAL, NULL},
/* Citizen Hyper Aqualand */ /* Citizen Hyper Aqualand */
@ -417,25 +404,6 @@ static const dc_descriptor_t g_descriptors[] = {
{"Ratio", "iX3M 2021 Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x73, 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 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", "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", "Jack", DC_FAMILY_DIVESYSTEM_IDIVE, 0x1000, DC_TRANSPORT_SERIAL, NULL},
{"Seac", "Guru", DC_FAMILY_DIVESYSTEM_IDIVE, 0x1002, DC_TRANSPORT_SERIAL, NULL}, {"Seac", "Guru", DC_FAMILY_DIVESYSTEM_IDIVE, 0x1002, DC_TRANSPORT_SERIAL, NULL},
/* Cochran Commander */ /* Cochran Commander */
@ -456,30 +424,16 @@ static const dc_descriptor_t g_descriptors[] = {
{"Liquivision", "Kaon", DC_FAMILY_LIQUIVISION_LYNX, 3, DC_TRANSPORT_SERIAL, NULL}, {"Liquivision", "Kaon", DC_FAMILY_LIQUIVISION_LYNX, 3, DC_TRANSPORT_SERIAL, NULL},
/* Sporasub */ /* Sporasub */
{"Sporasub", "SP2", DC_FAMILY_SPORASUB_SP2, 0, DC_TRANSPORT_SERIAL, NULL}, {"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 // Not merged upstream yet
/* Garmin -- model numbers as defined in FIT format; USB product id is (0x4000 | model) */ /* 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 we are using the model of the global model - the APAC model is 3702 */
/* for the Mk2/Mk3 we are using the model of the Mk2 global model */ {"Garmin", "Descent Mk1", DC_FAMILY_GARMIN, 2859, DC_TRANSPORT_USBSTORAGE, dc_filter_garmin},
/* see garmin_parser.c for a more comprehensive list of models */ {"Garmin", "Descent Mk2/Mk2i", DC_FAMILY_GARMIN, 3258, DC_TRANSPORT_USBSTORAGE, dc_filter_garmin},
{"Garmin", "Descent Mk1", DC_FAMILY_GARMIN, 2859, DC_TRANSPORT_USBSTORAGE, NULL}, /* Deepblu */
{"Garmin", "Descent Mk2(i)/Mk3(i)", DC_FAMILY_GARMIN, 3258, DC_TRANSPORT_USBSTORAGE, NULL}, {"Deepblu", "Cosmiq+", DC_FAMILY_DEEPBLU, 0, DC_TRANSPORT_BLE, dc_filter_deepblu},
{"FIT", "File import", DC_FAMILY_GARMIN, 0, DC_TRANSPORT_USBSTORAGE, NULL }, /* Oceans S1 */
{ "Oceans", "S1", DC_FAMILY_OCEANS_S1, 0, DC_TRANSPORT_BLE, dc_filter_oceans },
}; };
static int static int
@ -518,15 +472,6 @@ dc_match_usb (const void *key, const void *value)
return k->vid == v->vid && k->pid == v->pid; 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 static int
dc_match_number_with_prefix (const void *key, const void *value) dc_match_number_with_prefix (const void *key, const void *value)
{ {
@ -567,13 +512,16 @@ dc_match_oceanic (const void *key, const void *value)
} }
static int 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) if (key == NULL)
return 1; return 1;
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
if (match (key, (const unsigned char *) values + i * size)) { if (match (key, (const unsigned char *) values + i * size)) {
if (params_src && params_dst) {
memcpy (params_dst, params_src, params_size);
}
return 1; return 1;
} }
} }
@ -588,8 +536,7 @@ static const char * const rfcomm[] = {
NULL NULL
}; };
static int static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, void *params)
dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const irda[] = { static const char * const irda[] = {
"Aladin Smart Com", "Aladin Smart Com",
@ -600,8 +547,8 @@ dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const v
"UWATEC Galileo", "UWATEC Galileo",
"UWATEC Galileo Sol", "UWATEC Galileo Sol",
}; };
static const dc_usbhid_desc_t usbhid[] = { static const dc_usb_desc_t usbhid[] = {
{0x2e6c, 0x3201}, // G2, G2 TEK {0x2e6c, 0x3201}, // G2
{0x2e6c, 0x3211}, // G2 Console {0x2e6c, 0x3211}, // G2 Console
{0x2e6c, 0x4201}, // G2 HUD {0x2e6c, 0x4201}, // G2 HUD
{0xc251, 0x2006}, // Aladin Square {0xc251, 0x2006}, // Aladin Square
@ -612,16 +559,12 @@ dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const v
"HUD", "HUD",
"A1", "A1",
"A2", "A2",
"G2 TEK",
"Galileo 3",
"Luna 2.0 AI",
"Luna 2.0",
}; };
if (transport == DC_TRANSPORT_IRDA) { if (transport == DC_TRANSPORT_IRDA) {
return DC_FILTER_INTERNAL (userdata, irda, 0, dc_match_name); return DC_FILTER_INTERNAL (userdata, irda, 0, dc_match_name);
} else if (transport == DC_TRANSPORT_USBHID) { } 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) { } else if (transport == DC_TRANSPORT_BLE) {
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name); return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name);
} }
@ -629,10 +572,9 @@ dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const v
return 1; return 1;
} }
static int static int dc_filter_suunto (dc_transport_t transport, const void *userdata, void *params)
dc_filter_suunto (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const dc_usbhid_desc_t usbhid[] = { static const dc_usb_desc_t usbhid[] = {
{0x1493, 0x0030}, // Eon Steel {0x1493, 0x0030}, // Eon Steel
{0x1493, 0x0033}, // Eon Core {0x1493, 0x0033}, // Eon Core
{0x1493, 0x0035}, // D5 {0x1493, 0x0035}, // D5
@ -646,7 +588,7 @@ dc_filter_suunto (dc_descriptor_t *descriptor, dc_transport_t transport, const v
}; };
if (transport == DC_TRANSPORT_USBHID) { 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) { } else if (transport == DC_TRANSPORT_BLE) {
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix); return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix);
} }
@ -654,8 +596,7 @@ dc_filter_suunto (dc_descriptor_t *descriptor, dc_transport_t transport, const v
return 1; return 1;
} }
static int static int dc_filter_hw (dc_transport_t transport, const void *userdata, void *params)
dc_filter_hw (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"OSTC", "OSTC",
@ -671,20 +612,16 @@ dc_filter_hw (dc_descriptor_t *descriptor, dc_transport_t transport, const void
return 1; return 1;
} }
static int static int dc_filter_shearwater (dc_transport_t transport, const void *userdata, void *params)
dc_filter_shearwater (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"Predator", "Predator",
"Petrel", "Petrel",
"Petrel 3",
"NERD", "NERD",
"NERD 2", "NERD 2",
"Perdix", "Perdix",
"Perdix 2",
"Teric", "Teric",
"Peregrine", "Peregrine",
"Tern"
}; };
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) { if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
@ -696,8 +633,7 @@ dc_filter_shearwater (dc_descriptor_t *descriptor, dc_transport_t transport, con
return 1; return 1;
} }
static int static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata, void *params)
dc_filter_tecdiving (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"DiveComputer", "DiveComputer",
@ -712,8 +648,7 @@ dc_filter_tecdiving (dc_descriptor_t *descriptor, dc_transport_t transport, cons
return 1; return 1;
} }
static int static int dc_filter_mares (dc_transport_t transport, const void *userdata, void *params)
dc_filter_mares (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"Mares bluelink pro", "Mares bluelink pro",
@ -727,13 +662,11 @@ dc_filter_mares (dc_descriptor_t *descriptor, dc_transport_t transport, const vo
return 1; return 1;
} }
static int static int dc_filter_divesystem (dc_transport_t transport, const void *userdata, void *params)
dc_filter_divesystem (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"DS", "DS",
"IX5M", "IX5M",
"RATIO-",
}; };
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) { if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
@ -743,12 +676,10 @@ dc_filter_divesystem (dc_descriptor_t *descriptor, dc_transport_t transport, con
return 1; return 1;
} }
static int static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, void *params)
dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const unsigned int model[] = { static const unsigned int model[] = {
0x4552, // Oceanic Pro Plus X 0x4552, // Oceanic Pro Plus X
0x455A, // Aqualung i750TC
0x4647, // Sherwood Sage 0x4647, // Sherwood Sage
0x4648, // Aqualung i300C 0x4648, // Aqualung i300C
0x4649, // Aqualung i200C 0x4649, // Aqualung i200C
@ -758,12 +689,8 @@ dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const
0x4654, // Oceanic Veo 4.0 0x4654, // Oceanic Veo 4.0
0x4655, // Sherwood Wisdom 4 0x4655, // Sherwood Wisdom 4
0x4656, // Oceanic Pro Plus 4 0x4656, // Oceanic Pro Plus 4
0x4741, // Apeks DSX
0x4742, // Sherwood Beacon 0x4742, // Sherwood Beacon
0x4743, // Aqualung i470TC 0x4743, // Aqualung i470TC
0x4744, // Aqualung i330R
0x4749, // Aqualung i200C (newer model)
0x474B, // Oceanic Geo Air
}; };
if (transport == DC_TRANSPORT_BLE) { if (transport == DC_TRANSPORT_BLE) {
@ -773,8 +700,7 @@ dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const
return 1; return 1;
} }
static int static int dc_filter_mclean(dc_transport_t transport, const void *userdata, void *params)
dc_filter_mclean(dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"McLean Extreme", "McLean Extreme",
@ -789,39 +715,38 @@ dc_filter_mclean(dc_descriptor_t *descriptor, dc_transport_t transport, const vo
return 1; return 1;
} }
static int static int dc_filter_atomic (dc_transport_t transport, const void *userdata, void *params)
dc_filter_atomic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const dc_usb_desc_t usb[] = { static const dc_usb_desc_t usb[] = {
{0x0471, 0x0888}, // Atomic Aquatics Cobalt {0x0471, 0x0888}, // Atomic Aquatics Cobalt
}; };
if (transport == DC_TRANSPORT_USB) { static const dc_usb_params_t usb_params = {
return DC_FILTER_INTERNAL (userdata, usb, 0, dc_match_usb); 0, 0x82, 0x02
}
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",
}; };
if (transport == DC_TRANSPORT_BLE) { if (transport == DC_TRANSPORT_USB) {
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name); return DC_FILTER_INTERNAL_WITH_PARAMS (userdata, usb, 0, dc_match_usb, params, &usb_params);
} }
return 1; return 1;
} }
static int // Not merged upstream yet
dc_filter_deepblu (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 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[] = { static const char * const bluetooth[] = {
"COSMIQ", "COSMIQ",
@ -834,30 +759,14 @@ dc_filter_deepblu (dc_descriptor_t *descriptor, dc_transport_t transport, const
return 1; return 1;
} }
static int static int dc_filter_oceans(dc_transport_t transport, const void* userdata, void *params)
dc_filter_oceans (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char* const ble[] = {
"S1", "S1",
}; };
if (transport == DC_TRANSPORT_BLE) { 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;
}
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 1; return 1;
@ -955,10 +864,10 @@ dc_descriptor_get_transports (dc_descriptor_t *descriptor)
} }
int 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 || userdata == NULL)
return 1; return 1;
return descriptor->filter (descriptor, transport, userdata); return descriptor->filter (transport, userdata, params);
} }

View File

@ -92,7 +92,7 @@ int
device_is_cancelled (dc_device_t *device); device_is_cancelled (dc_device_t *device);
dc_status_t 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 #ifdef __cplusplus
} }

View File

@ -38,7 +38,6 @@
#include "oceanic_atom2.h" #include "oceanic_atom2.h"
#include "oceanic_veo250.h" #include "oceanic_veo250.h"
#include "oceanic_vtpro.h" #include "oceanic_vtpro.h"
#include "pelagic_i330r.h"
#include "mares_darwin.h" #include "mares_darwin.h"
#include "mares_iconhd.h" #include "mares_iconhd.h"
#include "mares_nemo.h" #include "mares_nemo.h"
@ -61,14 +60,11 @@
#include "mclean_extreme.h" #include "mclean_extreme.h"
#include "liquivision_lynx.h" #include "liquivision_lynx.h"
#include "sporasub_sp2.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 // Not merged upstream yet
#include "garmin.h" #include "garmin.h"
#include "deepblu.h"
#include "oceans_s1.h"
#include "device-private.h" #include "device-private.h"
#include "context-private.h" #include "context-private.h"
@ -166,9 +162,6 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
case DC_FAMILY_OCEANIC_ATOM2: case DC_FAMILY_OCEANIC_ATOM2:
rc = oceanic_atom2_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor)); rc = oceanic_atom2_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
break; 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: case DC_FAMILY_MARES_NEMO:
rc = mares_nemo_device_open (&device, context, iostream); rc = mares_nemo_device_open (&device, context, iostream);
break; break;
@ -235,21 +228,6 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
case DC_FAMILY_SPORASUB_SP2: case DC_FAMILY_SPORASUB_SP2:
rc = sporasub_sp2_device_open (&device, context, iostream); rc = sporasub_sp2_device_open (&device, context, iostream);
break; 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: default:
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
@ -257,6 +235,12 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
case DC_FAMILY_GARMIN: case DC_FAMILY_GARMIN:
rc = garmin_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor)); rc = garmin_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
break; 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; *out = device;
@ -370,7 +354,7 @@ dc_device_dump (dc_device_t *device, dc_buffer_t *buffer)
dc_status_t 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) if (device == NULL)
return DC_STATUS_UNSUPPORTED; return DC_STATUS_UNSUPPORTED;
@ -391,7 +375,7 @@ device_dump_read (dc_device_t *device, unsigned int address, unsigned char data[
len = blocksize; len = blocksize;
// Read the packet. // 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) if (rc != DC_STATUS_SUCCESS)
return rc; return rc;
@ -428,9 +412,6 @@ dc_device_timesync (dc_device_t *device, const dc_datetime_t *datetime)
if (device->vtable->timesync == NULL) if (device->vtable->timesync == NULL)
return DC_STATUS_UNSUPPORTED; return DC_STATUS_UNSUPPORTED;
if (datetime == NULL)
return DC_STATUS_INVALIDARGS;
return device->vtable->timesync (device, datetime); return device->vtable->timesync (device, datetime);
} }

View File

@ -35,7 +35,7 @@ dc_status_t
diverite_nitekq_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); diverite_nitekq_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t 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 #ifdef __cplusplus
} }

View File

@ -49,6 +49,7 @@ struct diverite_nitekq_parser_t {
double maxdepth; 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_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_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static dc_status_t diverite_nitekq_parser_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 = { static const dc_parser_vtable_t diverite_nitekq_parser_vtable = {
sizeof(diverite_nitekq_parser_t), sizeof(diverite_nitekq_parser_t),
DC_FAMILY_DIVERITE_NITEKQ, DC_FAMILY_DIVERITE_NITEKQ,
NULL, /* set_clock */ diverite_nitekq_parser_set_data, /* set_data */
NULL, /* set_atmospheric */
NULL, /* set_density */
diverite_nitekq_parser_get_datetime, /* datetime */ diverite_nitekq_parser_get_datetime, /* datetime */
diverite_nitekq_parser_get_field, /* fields */ diverite_nitekq_parser_get_field, /* fields */
diverite_nitekq_parser_samples_foreach, /* samples_foreach */ diverite_nitekq_parser_samples_foreach, /* samples_foreach */
@ -67,7 +66,7 @@ static const dc_parser_vtable_t diverite_nitekq_parser_vtable = {
dc_status_t 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; 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; return DC_STATUS_INVALIDARGS;
// Allocate memory. // 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) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; 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 static dc_status_t
diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) 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; *((unsigned int *) value) = parser->ngasmixes;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = parser->he[flags] / 100.0; gasmix->helium = parser->he[flags] / 100.0;
gasmix->oxygen = parser->o2[flags] / 100.0; gasmix->oxygen = parser->o2[flags] / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; 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 (seconds).
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Gas change // Gas change
if (gasmix != gasmix_previous) { if (gasmix != gasmix_previous) {
sample.gasmix = gasmix; sample.gasmix = gasmix;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix_previous = gasmix; gasmix_previous = gasmix;
} }
@ -274,7 +279,7 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
else else
sample.depth = depth * FEET / 10.0; sample.depth = depth * FEET / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
offset += 2; offset += 2;
if (type == 3) { if (type == 3) {
@ -285,9 +290,8 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
if (offset + 1 > size) if (offset + 1 > size)
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
unsigned int ppo2 = data[offset]; unsigned int ppo2 = data[offset];
sample.ppo2.sensor = DC_SENSOR_NONE; sample.ppo2 = ppo2 / 100.0;
sample.ppo2.value = ppo2 / 100.0; if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
if (callback) callback (DC_SAMPLE_PPO2, &sample, userdata);
offset++; offset++;
} }
} else { } else {

View File

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

View File

@ -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

View File

@ -29,7 +29,8 @@
#include "platform.h" #include "platform.h"
#include "checksum.h" #include "checksum.h"
#include "array.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) #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_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_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_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 = { static const dc_device_vtable_t divesystem_idive_device_vtable = {
sizeof(divesystem_idive_device_t), sizeof(divesystem_idive_device_t),
@ -114,7 +114,7 @@ static const dc_device_vtable_t divesystem_idive_device_vtable = {
NULL, /* dump */ NULL, /* dump */
divesystem_idive_device_foreach, /* foreach */ divesystem_idive_device_foreach, /* foreach */
divesystem_idive_device_timesync, /* timesync */ divesystem_idive_device_timesync, /* timesync */
divesystem_idive_device_close /* close */ NULL /* close */
}; };
static const divesystem_idive_commands_t idive = { 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; dc_status_t status = DC_STATUS_SUCCESS;
divesystem_idive_device_t *device = NULL; divesystem_idive_device_t *device = NULL;
dc_transport_t transport = dc_iostream_get_transport (iostream);
if (out == NULL) if (out == NULL)
return DC_STATUS_INVALIDARGS; 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. // Set the default values.
device->iostream = iostream;
memset (device->fingerprint, 0, sizeof (device->fingerprint)); memset (device->fingerprint, 0, sizeof (device->fingerprint));
device->model = model; 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). // Set the serial communication protocol (115200 8N1).
status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
if (status != DC_STATUS_SUCCESS) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the terminal attributes."); ERROR (context, "Failed to set the terminal attributes.");
goto error_free_iostream; goto error_free;
} }
// Set the timeout for receiving data (1000ms). // Set the timeout for receiving data (1000ms).
status = dc_iostream_set_timeout (device->iostream, 1000); status = dc_iostream_set_timeout (device->iostream, 1000);
if (status != DC_STATUS_SUCCESS) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to set the timeout."); ERROR (context, "Failed to set the timeout.");
goto error_free_iostream; goto error_free;
} }
// Make sure everything is in a sane state. // 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; return DC_STATUS_SUCCESS;
error_free_iostream:
if (transport == DC_TRANSPORT_BLE) {
dc_iostream_close (device->iostream);
}
error_free: error_free:
dc_device_deallocate ((dc_device_t *) device); dc_device_deallocate ((dc_device_t *) device);
return status; 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 static dc_status_t
divesystem_idive_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size) 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[0] = START;
packet[1] = csize; packet[1] = csize;
memcpy(packet + 2, command, 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 + 2] = (crc >> 8) & 0xFF;
packet[csize + 3] = (crc ) & 0xFF; packet[csize + 3] = (crc ) & 0xFF;
@ -321,7 +294,7 @@ divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answe
// Verify the checksum. // Verify the checksum.
unsigned short crc = array_uint16_be (packet + len + 2); 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) { if (crc != ccrc) {
ERROR (abstract->context, "Unexpected packet checksum."); ERROR (abstract->context, "Unexpected packet checksum.");
return DC_STATUS_PROTOCOL; 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; return DC_STATUS_UNSUPPORTED;
} }
if (datetime == NULL) {
ERROR (abstract->context, "Invalid parameter specified.");
return DC_STATUS_INVALIDARGS;
}
// Get the UTC timestamp. // Get the UTC timestamp.
dc_ticks_t timestamp = dc_datetime_mktime(datetime); dc_ticks_t timestamp = dc_datetime_mktime(datetime);
if (timestamp == -1) { if (timestamp == -1) {

View File

@ -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); divesystem_idive_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
dc_status_t 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 #ifdef __cplusplus
} }

View File

@ -26,10 +26,11 @@
#include "parser-private.h" #include "parser-private.h"
#include "array.h" #include "array.h"
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
#define ISINSTANCE(parser) dc_device_isinstance((parser), &divesystem_idive_parser_vtable) #define ISINSTANCE(parser) dc_device_isinstance((parser), &divesystem_idive_parser_vtable)
#define ISIX3M(model) ((model) >= 0x21) #define ISIX3M(model) ((model) >= 0x21)
#define ISIX3M2(model) ((model) >= 0x60 && (model) < 0x1000)
#define SZ_HEADER_IDIVE 0x32 #define SZ_HEADER_IDIVE 0x32
#define SZ_SAMPLE_IDIVE 0x2A #define SZ_SAMPLE_IDIVE 0x2A
@ -49,18 +50,6 @@
#define FREEDIVE 4 #define FREEDIVE 4
#define INVALID 0xFFFFFFFF #define INVALID 0xFFFFFFFF
#define BUHLMANN 0
#define VPM 1
#define DUAL 2
#define IX3M2_BUHLMANN 0
#define IX3M2_ZHL16B 1
#define IX3M2_ZHL16C 2
#define IX3M2_VPM 3
#define REC_SAMPLE 0
#define REC_INFO 1
typedef struct divesystem_idive_parser_t divesystem_idive_parser_t; typedef struct divesystem_idive_parser_t divesystem_idive_parser_t;
typedef struct divesystem_idive_gasmix_t { typedef struct divesystem_idive_gasmix_t {
@ -87,11 +76,9 @@ struct divesystem_idive_parser_t {
unsigned int ntanks; unsigned int ntanks;
divesystem_idive_gasmix_t gasmix[NGASMIXES]; divesystem_idive_gasmix_t gasmix[NGASMIXES];
divesystem_idive_tank_t tank[NTANKS]; divesystem_idive_tank_t tank[NTANKS];
unsigned int algorithm;
unsigned int gf_low;
unsigned int gf_high;
}; };
static dc_status_t divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
static dc_status_t divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static dc_status_t divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -99,9 +86,7 @@ static dc_status_t divesystem_idive_parser_samples_foreach (dc_parser_t *abstrac
static const dc_parser_vtable_t divesystem_idive_parser_vtable = { static const dc_parser_vtable_t divesystem_idive_parser_vtable = {
sizeof(divesystem_idive_parser_t), sizeof(divesystem_idive_parser_t),
DC_FAMILY_DIVESYSTEM_IDIVE, DC_FAMILY_DIVESYSTEM_IDIVE,
NULL, /* set_clock */ divesystem_idive_parser_set_data, /* set_data */
NULL, /* set_atmospheric */
NULL, /* set_density */
divesystem_idive_parser_get_datetime, /* datetime */ divesystem_idive_parser_get_datetime, /* datetime */
divesystem_idive_parser_get_field, /* fields */ divesystem_idive_parser_get_field, /* fields */
divesystem_idive_parser_samples_foreach, /* samples_foreach */ divesystem_idive_parser_samples_foreach, /* samples_foreach */
@ -110,7 +95,7 @@ static const dc_parser_vtable_t divesystem_idive_parser_vtable = {
dc_status_t dc_status_t
divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model) divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{ {
divesystem_idive_parser_t *parser = NULL; divesystem_idive_parser_t *parser = NULL;
@ -118,7 +103,7 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, const
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (divesystem_idive_parser_t *) dc_parser_allocate (context, &divesystem_idive_parser_vtable, data, size); parser = (divesystem_idive_parser_t *) dc_parser_allocate (context, &divesystem_idive_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -146,10 +131,6 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, const
parser->tank[i].beginpressure = 0; parser->tank[i].beginpressure = 0;
parser->tank[i].endpressure = 0; parser->tank[i].endpressure = 0;
} }
parser->algorithm = INVALID;
parser->gf_low = INVALID;
parser->gf_high = INVALID;
*out = (dc_parser_t*) parser; *out = (dc_parser_t*) parser;
@ -157,6 +138,32 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, const
} }
static dc_status_t
divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
divesystem_idive_parser_t *parser = (divesystem_idive_parser_t *) abstract;
// Reset the cache.
parser->cached = 0;
parser->divemode = INVALID;
parser->divetime = 0;
parser->maxdepth = 0;
parser->ngasmixes = 0;
parser->ntanks = 0;
for (unsigned int i = 0; i < NGASMIXES; ++i) {
parser->gasmix[i].oxygen = 0;
parser->gasmix[i].helium = 0;
}
for (unsigned int i = 0; i < NTANKS; ++i) {
parser->tank[i].id = 0;
parser->tank[i].beginpressure = 0;
parser->tank[i].endpressure = 0;
}
return DC_STATUS_SUCCESS;
}
static dc_status_t static dc_status_t
divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -275,7 +282,6 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
dc_tank_t *tank = (dc_tank_t *) value; dc_tank_t *tank = (dc_tank_t *) value;
dc_salinity_t *water = (dc_salinity_t *) value; dc_salinity_t *water = (dc_salinity_t *) value;
dc_decomodel_t *decomodel = (dc_decomodel_t *) value;
if (value) { if (value) {
switch (type) { switch (type) {
@ -289,7 +295,6 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
*((unsigned int *) value) = parser->ngasmixes; *((unsigned int *) value) = parser->ngasmixes;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = parser->gasmix[flags].helium / 100.0; gasmix->helium = parser->gasmix[flags].helium / 100.0;
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0; gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -304,7 +309,6 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
tank->beginpressure = parser->tank[flags].beginpressure; tank->beginpressure = parser->tank[flags].beginpressure;
tank->endpressure = parser->tank[flags].endpressure; tank->endpressure = parser->tank[flags].endpressure;
tank->gasmix = DC_GASMIX_UNKNOWN; tank->gasmix = DC_GASMIX_UNKNOWN;
tank->usage = DC_TANK_USAGE_NONE;
break; break;
case DC_FIELD_ATMOSPHERIC: case DC_FIELD_ATMOSPHERIC:
if (ISIX3M(parser->model)) { if (ISIX3M(parser->model)) {
@ -318,7 +322,7 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
water->density = 0.0; water->density = 0.0;
break; break;
case DC_FIELD_DIVEMODE: case DC_FIELD_DIVEMODE:
if (parser->divemode == INVALID) if (parser->divemode == 0xFFFFFFFF)
return DC_STATUS_UNSUPPORTED; return DC_STATUS_UNSUPPORTED;
switch (parser->divemode) { switch (parser->divemode) {
case OC: case OC:
@ -341,46 +345,6 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
break; break;
case DC_FIELD_DECOMODEL:
if (parser->algorithm == INVALID)
return DC_STATUS_UNSUPPORTED;
if (ISIX3M2(parser->model)) {
switch (parser->algorithm) {
case IX3M2_BUHLMANN:
case IX3M2_ZHL16B:
case IX3M2_ZHL16C:
decomodel->type = DC_DECOMODEL_BUHLMANN;
decomodel->conservatism = 0;
decomodel->params.gf.low = parser->gf_low;
decomodel->params.gf.high = parser->gf_high;
break;
case IX3M2_VPM:
decomodel->type = DC_DECOMODEL_VPM;
decomodel->conservatism = 0;
break;
default:
ERROR (abstract->context, "Unknown deco algorithm %02x.", parser->algorithm);
return DC_STATUS_DATAFORMAT;
}
} else {
switch (parser->algorithm) {
case BUHLMANN:
case DUAL:
decomodel->type = DC_DECOMODEL_BUHLMANN;
decomodel->conservatism = 0;
decomodel->params.gf.low = parser->gf_low;
decomodel->params.gf.high = parser->gf_high;
break;
case VPM:
decomodel->type = DC_DECOMODEL_VPM;
decomodel->conservatism = 0;
break;
default:
ERROR (abstract->context, "Unknown deco algorithm %02x.", parser->algorithm);
return DC_STATUS_DATAFORMAT;
}
}
break;
default: default:
return DC_STATUS_UNSUPPORTED; return DC_STATUS_UNSUPPORTED;
} }
@ -403,17 +367,12 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
unsigned int ntanks = 0; unsigned int ntanks = 0;
divesystem_idive_gasmix_t gasmix[NGASMIXES] = {0}; divesystem_idive_gasmix_t gasmix[NGASMIXES] = {0};
divesystem_idive_tank_t tank[NTANKS] = {0}; divesystem_idive_tank_t tank[NTANKS] = {0};
unsigned int o2_previous = INVALID; unsigned int o2_previous = 0xFFFFFFFF;
unsigned int he_previous = INVALID; unsigned int he_previous = 0xFFFFFFFF;
unsigned int mode_previous = INVALID; unsigned int mode_previous = INVALID;
unsigned int divemode = INVALID; unsigned int divemode = INVALID;
unsigned int tank_previous = INVALID; unsigned int tank_previous = INVALID;
unsigned int tank_idx = INVALID; unsigned int tank_idx = INVALID;
unsigned int algorithm = INVALID;
unsigned int algorithm_previous = INVALID;
unsigned int gf_low = INVALID;
unsigned int gf_high = INVALID;
unsigned int have_bearing = 0;
unsigned int firmware = 0; unsigned int firmware = 0;
unsigned int apos4 = 0; unsigned int apos4 = 0;
@ -442,37 +401,27 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
while (offset + samplesize <= size) { while (offset + samplesize <= size) {
dc_sample_value_t sample = {0}; dc_sample_value_t sample = {0};
// Get the record type.
unsigned int type = ISIX3M(parser->model) ?
array_uint16_le (data + offset + 52) :
REC_SAMPLE;
if (type != REC_SAMPLE) {
// Skip non-sample records.
offset += samplesize;
continue;
}
// Time (seconds). // Time (seconds).
unsigned int timestamp = array_uint32_le (data + offset + 2); unsigned int timestamp = array_uint32_le (data + offset + 2);
if (timestamp <= time && time != 0) { if (timestamp <= time) {
ERROR (abstract->context, "Timestamp moved backwards (%u %u).", timestamp, time); ERROR (abstract->context, "Timestamp moved backwards.");
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
time = timestamp; time = timestamp;
sample.time = timestamp * 1000; sample.time = timestamp;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/10 m). // Depth (1/10 m).
unsigned int depth = array_uint16_le (data + offset + 6); unsigned int depth = array_uint16_le (data + offset + 6);
if (maxdepth < depth) if (maxdepth < depth)
maxdepth = depth; maxdepth = depth;
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Temperature (Celsius). // Temperature (Celsius).
signed int temperature = (signed short) array_uint16_le (data + offset + 8); signed int temperature = (signed short) array_uint16_le (data + offset + 8);
sample.temperature = temperature / 10.0; sample.temperature = temperature / 10.0;
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
// Dive mode // Dive mode
unsigned int mode = data[offset + 18]; unsigned int mode = data[offset + 18];
@ -486,27 +435,11 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
divemode = mode; divemode = mode;
} }
// Deco model
unsigned int s_algorithm = data[offset + 14];
unsigned int s_gf_high = data[offset + 15];
unsigned int s_gf_low = data[offset + 16];
if (s_algorithm != algorithm_previous) {
if (algorithm_previous != INVALID) {
WARNING (abstract->context, "Deco algorithm changed from %02x to %02x.", algorithm_previous, s_algorithm);
}
algorithm_previous = s_algorithm;
}
if (algorithm == INVALID) {
algorithm = s_algorithm;
gf_low = s_gf_low;
gf_high = s_gf_high;
}
// Setpoint // Setpoint
if (mode == SCR || mode == CCR) { if (mode == SCR || mode == CCR) {
unsigned int setpoint = array_uint16_le (data + offset + 19); unsigned int setpoint = array_uint16_le (data + offset + 19);
sample.setpoint = setpoint / 1000.0; sample.setpoint = setpoint / 1000.0;
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata); if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
} }
// Gaschange. // Gaschange.
@ -533,7 +466,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
} }
sample.gasmix = i; sample.gasmix = i;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
o2_previous = o2; o2_previous = o2;
he_previous = he; he_previous = he;
} }
@ -551,20 +484,18 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
if (decostop) { if (decostop) {
sample.deco.type = DC_DECO_DECOSTOP; sample.deco.type = DC_DECO_DECOSTOP;
sample.deco.depth = decostop / 10.0; sample.deco.depth = decostop / 10.0;
sample.deco.time = decotime; sample.deco.time = apos4 ? decotime : tts;
sample.deco.tts = tts;
} else { } else {
sample.deco.type = DC_DECO_NDL; sample.deco.type = DC_DECO_NDL;
sample.deco.depth = 0.0; sample.deco.depth = 0.0;
sample.deco.time = tts; sample.deco.time = tts;
sample.deco.tts = 0;
} }
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata); if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
// CNS // CNS
unsigned int cns = array_uint16_le (data + offset + 29); unsigned int cns = array_uint16_le (data + offset + 29);
sample.cns = cns / 100.0; sample.cns = cns / 100.0;
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata); if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
// Tank Pressure // Tank Pressure
if (samplesize == SZ_SAMPLE_IX3M_APOS4) { if (samplesize == SZ_SAMPLE_IX3M_APOS4) {
@ -572,11 +503,6 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
unsigned int flags = data[offset + 47] & 0xF0; unsigned int flags = data[offset + 47] & 0xF0;
unsigned int pressure = data[offset + 49]; unsigned int pressure = data[offset + 49];
if (flags & 0x20) {
// 300 bar transmitter.
pressure *= 2;
}
if (flags & 0x80) { if (flags & 0x80) {
// No active transmitter available // No active transmitter available
} else if (flags & 0x40) { } else if (flags & 0x40) {
@ -585,7 +511,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
sample.event.time = 0; sample.event.time = 0;
sample.event.flags = 0; sample.event.flags = 0;
sample.event.value = 0; sample.event.value = 0;
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
} else { } else {
// Get the index of the tank. // Get the index of the tank.
if (id != tank_previous) { if (id != tank_previous) {
@ -615,20 +541,10 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
if (tank_idx < ntanks) { if (tank_idx < ntanks) {
sample.pressure.tank = tank_idx; sample.pressure.tank = tank_idx;
sample.pressure.value = pressure; sample.pressure.value = pressure;
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata); if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
tank[tank_idx].endpressure = pressure; tank[tank_idx].endpressure = pressure;
} }
} }
// Compass bearing
unsigned int bearing = array_uint16_le (data + offset + 50);
if (bearing != 0) {
have_bearing = 1; // Stop ignoring zero values.
}
if (have_bearing && bearing != 0xFFFF) {
sample.bearing = bearing;
if (callback) callback (DC_SAMPLE_BEARING, &sample, userdata);
}
} }
offset += samplesize; offset += samplesize;
@ -646,9 +562,6 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
parser->maxdepth = maxdepth; parser->maxdepth = maxdepth;
parser->divetime = time; parser->divetime = time;
parser->divemode = divemode; parser->divemode = divemode;
parser->algorithm = algorithm;
parser->gf_low = gf_low;
parser->gf_high = gf_high;
parser->cached = 1; parser->cached = 1;
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;

View File

@ -9,7 +9,7 @@
* The field cache 'string' interface has some simple rules: * The field cache 'string' interface has some simple rules:
* the "descriptor" part is assumed to be a static allocation, * the "descriptor" part is assumed to be a static allocation,
* while the "value" is something that this interface will * while the "value" is something that this interface will
* always allocate with 'strdup()', so you can generate it * alway sallocate with 'strdup()', so you can generate it
* dynamically on the stack or whatever without having to * dynamically on the stack or whatever without having to
* worry about it. * worry about it.
*/ */
@ -71,9 +71,6 @@ dc_status_t dc_field_get_string(dc_field_cache_t *cache, unsigned idx, dc_field_
dc_status_t dc_status_t
dc_field_get(dc_field_cache_t *cache, dc_field_type_t type, unsigned int flags, void* value) dc_field_get(dc_field_cache_t *cache, dc_field_type_t type, unsigned int flags, void* value)
{ {
if (!value)
return DC_STATUS_INVALIDARGS;
if (!(cache->initialized & (1 << type))) if (!(cache->initialized & (1 << type)))
return DC_STATUS_UNSUPPORTED; return DC_STATUS_UNSUPPORTED;
@ -85,31 +82,16 @@ dc_field_get(dc_field_cache_t *cache, dc_field_type_t type, unsigned int flags,
case DC_FIELD_AVGDEPTH: case DC_FIELD_AVGDEPTH:
return DC_FIELD_VALUE(*cache, value, AVGDEPTH); return DC_FIELD_VALUE(*cache, value, AVGDEPTH);
case DC_FIELD_GASMIX_COUNT: case DC_FIELD_GASMIX_COUNT:
return DC_FIELD_VALUE(*cache, value, GASMIX_COUNT);
case DC_FIELD_TANK_COUNT: case DC_FIELD_TANK_COUNT:
return DC_FIELD_VALUE(*cache, value, TANK_COUNT); return DC_FIELD_VALUE(*cache, value, GASMIX_COUNT);
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
if (flags >= MAXGASES) if (flags >= MAXGASES)
break; break;
return DC_FIELD_INDEX(*cache, value, GASMIX, flags); return DC_FIELD_INDEX(*cache, value, GASMIX, flags);
case DC_FIELD_SALINITY: case DC_FIELD_SALINITY:
return DC_FIELD_VALUE(*cache, value, SALINITY); return DC_FIELD_VALUE(*cache, value, SALINITY);
case DC_FIELD_ATMOSPHERIC:
return DC_FIELD_VALUE(*cache, value, ATMOSPHERIC);
case DC_FIELD_DIVEMODE: case DC_FIELD_DIVEMODE:
return DC_FIELD_VALUE(*cache, value, DIVEMODE); return DC_FIELD_VALUE(*cache, value, DIVEMODE);
case DC_FIELD_TANK:
if (flags >= MAXGASES)
break;
dc_tank_t *tank = (dc_tank_t *) value;
tank->volume = cache->tanksize[flags];
tank->gasmix = flags;
tank->workpressure = cache->tankworkingpressure[flags];
tank->type = cache->tankinfo[flags];
return DC_STATUS_SUCCESS;
case DC_FIELD_STRING: case DC_FIELD_STRING:
return dc_field_get_string(cache, flags, (dc_field_string_t *)value); return dc_field_get_string(cache, flags, (dc_field_string_t *)value);
default: default:

View File

@ -14,7 +14,6 @@ typedef struct dc_field_cache {
double ATMOSPHERIC; double ATMOSPHERIC;
dc_divemode_t DIVEMODE; dc_divemode_t DIVEMODE;
unsigned int GASMIX_COUNT; unsigned int GASMIX_COUNT;
unsigned int TANK_COUNT;
dc_salinity_t SALINITY; dc_salinity_t SALINITY;
dc_gasmix_t GASMIX[MAXGASES]; dc_gasmix_t GASMIX[MAXGASES];
@ -23,11 +22,10 @@ typedef struct dc_field_cache {
double highsetpoint; double highsetpoint;
double customsetpoint; double customsetpoint;
// This (along with GASMIX) should be something like // This (slong with GASMIX) should be something like
// dc_tank_t TANK[MAXGASES] // dc_tank_t TANK[MAXGASES]
// but that's for later // but that's for later
dc_tankinfo_t tankinfo[MAXGASES]; dc_tankinfo_t tankinfo[MAXGASES];
dc_tank_usage_t tankusage[MAXGASES];
double tanksize[MAXGASES]; double tanksize[MAXGASES];
double tankworkingpressure[MAXGASES]; double tankworkingpressure[MAXGASES];

View File

@ -52,7 +52,6 @@ typedef struct garmin_device_t {
dc_device_t base; dc_device_t base;
dc_iostream_t *iostream; dc_iostream_t *iostream;
unsigned char fingerprint[FIT_NAME_SIZE]; unsigned char fingerprint[FIT_NAME_SIZE];
unsigned int model;
#ifdef HAVE_LIBMTP #ifdef HAVE_LIBMTP
unsigned char use_mtp; unsigned char use_mtp;
LIBMTP_mtpdevice_t *mtp_device; LIBMTP_mtpdevice_t *mtp_device;
@ -93,7 +92,6 @@ garmin_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *ios
// Set the default values. // Set the default values.
device->iostream = iostream; device->iostream = iostream;
memset(device->fingerprint, 0, sizeof(device->fingerprint)); memset(device->fingerprint, 0, sizeof(device->fingerprint));
device->model = model;
#ifdef HAVE_LIBMTP #ifdef HAVE_LIBMTP
// for a Descent Mk2/Mk2i, we have to use MTP to access its storage; // for a Descent Mk2/Mk2i, we have to use MTP to access its storage;
@ -101,6 +99,7 @@ garmin_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *ios
// in order to have only one entry for the Mk2, we don't use the Mk2/APAC model number in our code // in order to have only one entry for the Mk2, we don't use the Mk2/APAC model number in our code
device->use_mtp = (model == (0x0FFF & DESCENT_MK2)); device->use_mtp = (model == (0x0FFF & DESCENT_MK2));
device->mtp_device = NULL; device->mtp_device = NULL;
DEBUG(context, "Found Garmin with model 0x%x which is a %s\n", model, (device->use_mtp ? "Mk2/Mk2i" : "Mk1"));
#endif #endif
*out = (dc_device_t *) device; *out = (dc_device_t *) device;
@ -137,69 +136,18 @@ garmin_device_close (dc_device_t *abstract)
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
} }
/*
* NOTE! The fingerprint is only the 24 first bytes of this,
* aka FIT_NAME_SIZE.
*/
#define FILE_NAME_SIZE 64
struct fit_file {
char name[FILE_NAME_SIZE + 1];
unsigned int mtp_id;
};
struct file_list { struct file_list {
int nr, allocated; int nr, allocated;
struct fit_file *array; struct fit_file *array;
}; };
static int
char_to_int(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'z')
return c - 'a' + 10;
if (c >= 'A' && c <= 'Z')
return c - 'A' + 10;
return 0;
}
/* C4ND0302.fit -> 2022-04-23-13-03-02.fit */
static void
parse_short_name(const char *name, char *output)
{
sprintf(output, "%d-%02d-%02d-%02d-%02d-%02d.fit", char_to_int(name[0]) + 2010, // Year
char_to_int(name[1]), // Month
char_to_int(name[2]), // Day
char_to_int(name[3]), // Hour
char_to_int(name[4]) * 10 + char_to_int(name[5]), // Minute
char_to_int(name[6]) * 10 + char_to_int(name[7])); // Second
}
static int name_cmp(const void *_a, const void *_b) static int name_cmp(const void *_a, const void *_b)
{ {
const struct fit_file *a = _a; const struct fit_file *a = _a;
const struct fit_file *b = _b; const struct fit_file *b = _b;
const char *a_name = a->name;
const char *b_name = b->name;
char a_buffer[FILE_NAME_SIZE];
char b_buffer[FILE_NAME_SIZE];
if (strlen(a_name) == 12) {
parse_short_name(a_name, a_buffer);
a_name = a_buffer;
}
if (strlen(b_name) == 12) {
parse_short_name(b_name, b_buffer);
b_name = b_buffer;
}
// Sort reverse string ordering (newest first), so use 'b,a' // Sort reverse string ordering (newest first), so use 'b,a'
return strcmp(b_name, a_name); return strcmp(b->name, a->name);
} }
/* /*
@ -212,16 +160,19 @@ static int
check_filename(dc_device_t *abstract, const char *name) check_filename(dc_device_t *abstract, const char *name)
{ {
int len = strlen(name); int len = strlen(name);
const char *explain = NULL;
DEBUG(abstract->context, " %s", name);
if (len < 5) if (len < 5)
return 0; explain = "name too short";
if (len >= FILE_NAME_SIZE) if (len >= FIT_NAME_SIZE)
return 0; explain = "name too long";
if (strncasecmp(name + len - 4, ".FIT", 4)) if (strncasecmp(name + len - 4, ".FIT", 4))
return 0; explain = "name lacks FIT suffix";
DEBUG(abstract->context, " %s - adding to list", name); DEBUG(abstract->context, " %s - %s", name, explain ? explain : "adding to list");
return 1; return explain == NULL;
} }
static dc_status_t static dc_status_t
@ -252,8 +203,8 @@ add_name(struct file_list *files, const char *name, unsigned int mtp_id)
* will zero-pad the end of the result buffer. * will zero-pad the end of the result buffer.
*/ */
struct fit_file *entry = files->array + files->nr++; struct fit_file *entry = files->array + files->nr++;
strncpy(entry->name, name, FILE_NAME_SIZE); strncpy(entry->name, name, FIT_NAME_SIZE);
entry->name[FILE_NAME_SIZE] = 0; // ensure it's null-terminated entry->name[FIT_NAME_SIZE] = 0; // ensure it's null-terminated
entry->mtp_id = mtp_id; entry->mtp_id = mtp_id;
} }
@ -330,16 +281,12 @@ mtp_get_file_list(dc_device_t *abstract, struct file_list *files)
for (i = 0; i < numrawdevices; i++) { for (i = 0; i < numrawdevices; i++) {
LIBMTP_devicestorage_t *storage; LIBMTP_devicestorage_t *storage;
// we only want to read from a Garmin Descent Mk2 device at this point // we only want to read from a Garmin Descent Mk2 device at this point
if (rawdevices[i].device_entry.vendor_id != GARMIN_VENDOR) { if (rawdevices[i].device_entry.vendor_id != GARMIN_VENDOR ||
(rawdevices[i].device_entry.product_id != DESCENT_MK2 && rawdevices[i].device_entry.product_id != DESCENT_MK2_APAC)) {
DEBUG(abstract->context, "Garmin/mtp: skipping raw device %04x/%04x", DEBUG(abstract->context, "Garmin/mtp: skipping raw device %04x/%04x",
rawdevices[i].device_entry.vendor_id, rawdevices[i].device_entry.product_id); rawdevices[i].device_entry.vendor_id, rawdevices[i].device_entry.product_id);
continue; continue;
} }
if (rawdevices[i].device_entry.product_id != DESCENT_MK2 && rawdevices[i].device_entry.product_id != DESCENT_MK2_APAC) {
DEBUG(abstract->context, "Garmin/mtp: skipping Garmin raw device %04x/%04x, as it is not a dive computer / does not support MTP",
rawdevices[i].device_entry.vendor_id, rawdevices[i].device_entry.product_id);
continue;
}
device->mtp_device = LIBMTP_Open_Raw_Device_Uncached(&rawdevices[i]); device->mtp_device = LIBMTP_Open_Raw_Device_Uncached(&rawdevices[i]);
if (device->mtp_device == NULL) { if (device->mtp_device == NULL) {
DEBUG(abstract->context, "Garmin/mtp: unable to open raw device %d", i); DEBUG(abstract->context, "Garmin/mtp: unable to open raw device %d", i);
@ -420,7 +367,7 @@ read_file(char *pathname, int pathlen, const char *name, dc_buffer_t *file)
int fd, rc; int fd, rc;
pathname[pathlen] = '/'; pathname[pathlen] = '/';
memcpy(pathname+pathlen+1, name, FILE_NAME_SIZE); memcpy(pathname+pathlen+1, name, FIT_NAME_SIZE);
fd = open(pathname, O_RDONLY | O_BINARY); fd = open(pathname, O_RDONLY | O_BINARY);
if (fd < 0) if (fd < 0)
@ -451,8 +398,8 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
garmin_device_t *device = (garmin_device_t *) abstract; garmin_device_t *device = (garmin_device_t *) abstract;
dc_parser_t *parser;
char pathname[PATH_MAX]; char pathname[PATH_MAX];
char pathname_input[PATH_MAX];
size_t pathlen; size_t pathlen;
struct file_list files = { struct file_list files = {
0, // nr 0, // nr
@ -464,10 +411,10 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
dc_status_t rc; dc_status_t rc;
// Read the directory name from the iostream // Read the directory name from the iostream
rc = dc_iostream_read(device->iostream, &pathname_input, sizeof(pathname_input)-1, &pathlen); rc = dc_iostream_read(device->iostream, &pathname, sizeof(pathname)-1, &pathlen);
if (rc != DC_STATUS_SUCCESS) if (rc != DC_STATUS_SUCCESS)
return rc; return rc;
pathname_input[pathlen] = 0; pathname[pathlen] = 0;
#ifdef HAVE_LIBMTP #ifdef HAVE_LIBMTP
// if the user passes in a path, don't try to read via MTP // if the user passes in a path, don't try to read via MTP
@ -478,11 +425,10 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
// The actual dives are under the "Garmin/Activity/" directory // The actual dives are under the "Garmin/Activity/" directory
// as FIT files, with names like "2018-08-20-10-23-30.fit". // as FIT files, with names like "2018-08-20-10-23-30.fit".
// Make sure our buffer is big enough. // Make sure our buffer is big enough.
if (pathlen + strlen("/Garmin/Activity/") + FILE_NAME_SIZE + 2 > PATH_MAX) { if (pathlen + strlen("/Garmin/Activity/") + FIT_NAME_SIZE + 2 > PATH_MAX) {
ERROR (abstract->context, "Invalid Garmin base directory '%s'", pathname_input); ERROR (abstract->context, "Invalid Garmin base directory '%s'", pathname);
return DC_STATUS_IO; return DC_STATUS_IO;
} }
strcpy(pathname, pathname_input);
if (pathlen && pathname[pathlen-1] != '/') if (pathlen && pathname[pathlen-1] != '/')
pathname[pathlen++] = '/'; pathname[pathlen++] = '/';
strcpy(pathname + pathlen, "Garmin/Activity"); strcpy(pathname + pathlen, "Garmin/Activity");
@ -500,13 +446,8 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
{ // slight coding style violation to deal with the non-MTP case { // slight coding style violation to deal with the non-MTP case
dir = opendir(pathname); dir = opendir(pathname);
if (!dir) { if (!dir) {
dir = opendir(pathname_input); ERROR (abstract->context, "Failed to open directory '%s'.", pathname);
if (!dir) { return DC_STATUS_IO;
ERROR (abstract->context, "Failed to open directory '%s' or '%s'.", pathname, pathname_input);
return DC_STATUS_IO;
}
strcpy(pathname, pathname_input);
pathlen = strlen(pathname);
} }
// Get the list of FIT files // Get the list of FIT files
rc = get_file_list(abstract, dir, &files); rc = get_file_list(abstract, dir, &files);
@ -541,12 +482,16 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
free(files.array); free(files.array);
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
} }
if ((rc = garmin_parser_create(&parser, abstract->context) != DC_STATUS_SUCCESS)) {
ERROR (abstract->context, "Failed to create parser for dive verification.");
free(files.array);
return rc;
}
dc_event_devinfo_t devinfo; dc_event_devinfo_t devinfo;
dc_event_devinfo_t *devinfo_p = &devinfo; dc_event_devinfo_t *devinfo_p = &devinfo;
for (int i = 0; i < files.nr; i++) { for (int i = 0; i < files.nr; i++) {
const char *name = files.array[i].name; const char *name = files.array[i].name;
dc_parser_t *parser;
const unsigned char *data; const unsigned char *data;
unsigned int size; unsigned int size;
short is_dive = 0; short is_dive = 0;
@ -572,14 +517,7 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
data = dc_buffer_get_data(file); data = dc_buffer_get_data(file);
size = dc_buffer_get_size(file); size = dc_buffer_get_size(file);
status = garmin_parser_create(&parser, abstract->context, data, size); is_dive = garmin_parser_is_dive(parser, data, size, devinfo_p);
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create parser for dive verification.");
free(files.array);
return rc;
}
is_dive = !device->model || garmin_parser_is_dive(parser, devinfo_p);
if (devinfo_p) { if (devinfo_p) {
// first time we came through here, let's emit the // first time we came through here, let's emit the
// devinfo and vendor events // devinfo and vendor events
@ -588,7 +526,6 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
} }
if (!is_dive) { if (!is_dive) {
DEBUG(abstract->context, "decided %s isn't a dive.", name); DEBUG(abstract->context, "decided %s isn't a dive.", name);
dc_parser_destroy(parser);
continue; continue;
} }
@ -597,10 +534,10 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
progress.current++; progress.current++;
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress); device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
dc_parser_destroy(parser);
} }
free(files.array); free(files.array);
dc_parser_destroy(parser);
dc_buffer_free(file); dc_buffer_free(file);
return status; return status;
} }

View File

@ -35,12 +35,12 @@ dc_status_t
garmin_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model); garmin_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
dc_status_t dc_status_t
garmin_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size); garmin_parser_create (dc_parser_t **parser, dc_context_t *context);
// we need to be able to call into the parser to check if the // we need to be able to call into the parser to check if the
// files that we find are actual dives // files that we find are actual dives
int int
garmin_parser_is_dive (dc_parser_t *abstract, dc_event_devinfo_t *devinfo_p); garmin_parser_is_dive (dc_parser_t *abstract, const unsigned char *data, unsigned int size, dc_event_devinfo_t *devinfo_p);
// The dive names are of the form "2018-08-20-10-23-30.fit" // The dive names are of the form "2018-08-20-10-23-30.fit"
// With the terminating zero, that's 24 bytes. // With the terminating zero, that's 24 bytes.
@ -49,6 +49,11 @@ garmin_parser_is_dive (dc_parser_t *abstract, dc_event_devinfo_t *devinfo_p);
// special fixed header in the parser data too. // special fixed header in the parser data too.
#define FIT_NAME_SIZE 24 #define FIT_NAME_SIZE 24
struct fit_file {
char name[FIT_NAME_SIZE + 1];
unsigned int mtp_id;
};
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

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