Compare commits
143 Commits
testbranch
...
Subsurface
| Author | SHA1 | Date | |
|---|---|---|---|
| d5f9b352fc | |||
| 311f8d05f4 | |||
| deaaeee7a1 | |||
| c281b04bfc | |||
| 132a3949fd | |||
| 27a37fc95a | |||
| d1106cb8ba | |||
|
|
9641883f2f | ||
|
|
c7e89eab11 | ||
|
|
9b12e8e638 | ||
|
|
d9c230820f | ||
|
|
5d321deb8a | ||
|
|
9f2674ee7c | ||
|
|
6bd1183c34 | ||
|
|
0c125489df | ||
|
|
fa224f5300 | ||
|
|
8f686ce1d8 | ||
|
|
a7fb341fb0 | ||
|
|
ff0023b8b4 | ||
|
|
6e65428fc8 | ||
|
|
89221475cf | ||
|
|
bff6f7c140 | ||
|
|
ca55a11ed5 | ||
|
|
bb502c6d8b | ||
|
|
792090566e | ||
|
|
62a29eea15 | ||
|
|
4bbfe1659e | ||
|
|
39bc2fe05c | ||
|
|
edfb1a9c67 | ||
|
|
d37cb91734 | ||
|
|
78710ab2f1 | ||
|
|
76170009b4 | ||
|
|
1d0aeecf65 | ||
|
|
de6696bc7f | ||
|
|
cfe345aa8e | ||
|
|
d47e1ce02b | ||
|
|
08d8c3e132 | ||
|
|
2d9008aff7 | ||
|
|
e1762fc8bd | ||
|
|
3c50e91a10 | ||
|
|
cb0164150e | ||
|
|
e83732e200 | ||
|
|
a7e7439cab | ||
|
|
072f0d4242 | ||
|
|
baa1c494c1 | ||
|
|
330cb88952 | ||
|
|
37421a1b9a | ||
|
|
fe9b47f4bd | ||
|
|
ed871137b1 | ||
|
|
4a9be44afd | ||
|
|
a985b11859 | ||
|
|
b2310e62d6 | ||
|
|
301fdbe364 | ||
|
|
beb348dbf6 | ||
|
|
5d36cc0798 | ||
|
|
993283d1c8 | ||
|
|
323804d5e6 | ||
|
|
ecc9e0b09b | ||
|
|
577b694087 | ||
|
|
58ea31e62e | ||
|
|
97b2c89aaa | ||
|
|
8bfbb94087 | ||
|
|
9cde393e5f | ||
|
|
9bc742d3ac | ||
|
|
a4cd21b811 | ||
|
|
f77e9c03fc | ||
|
|
f818a5a92a | ||
|
|
3e39cb427a | ||
|
|
e81eca685a | ||
|
|
dc8f32609e | ||
|
|
196cfdf4df | ||
|
|
503afc1a5f | ||
|
|
e02df46a2b | ||
|
|
2879bd69a5 | ||
|
|
4a2dec531e | ||
|
|
67cd1cc0fd | ||
|
|
929ce47155 | ||
|
|
147d3df635 | ||
|
|
4aa70c9e2a | ||
|
|
571df62ce5 | ||
|
|
ceaaba3e77 | ||
|
|
1222041b46 | ||
|
|
3733b87ac9 | ||
|
|
0afd62d7af | ||
|
|
3a68af418e | ||
|
|
ff0328537e | ||
|
|
3d82d6796f | ||
|
|
25bd1f9853 | ||
|
|
c16530b8ab | ||
|
|
d4402aa296 | ||
|
|
13705f2b2d | ||
|
|
ee147afceb | ||
|
|
b13ad617ac | ||
|
|
838717dbae | ||
|
|
436063c74d | ||
|
|
763fc68741 | ||
|
|
9b7aa813e0 | ||
|
|
63f5a4d652 | ||
|
|
679db0bae6 | ||
|
|
0a4f37770f | ||
|
|
4e24b3a277 | ||
|
|
becb8bd36e | ||
|
|
4b383a778e | ||
|
|
b1ff2c6a8e | ||
|
|
bca8f9e2d2 | ||
|
|
a34e909a84 | ||
|
|
db9371cf9f | ||
|
|
070de23b83 | ||
|
|
49aa12b172 | ||
|
|
2f1b99f2f9 | ||
|
|
6c3bbb2cc7 | ||
|
|
1c8cd096b5 | ||
|
|
40c95ca02a | ||
|
|
72ddd6a439 | ||
|
|
d4472b758f | ||
|
|
b0e77fd05f | ||
|
|
cee9a2e926 | ||
|
|
9c38ae3e01 | ||
|
|
629d567381 | ||
|
|
bec4a747ff | ||
|
|
43f48af418 | ||
|
|
e45c62b028 | ||
|
|
767a2fad91 | ||
|
|
083b1eb8de | ||
|
|
118f6d79ba | ||
|
|
cf221de9b7 | ||
|
|
3a2dc6cce4 | ||
|
|
86fd58c8c6 | ||
|
|
1930b9eb59 | ||
|
|
554855cc7d | ||
|
|
27b471e76b | ||
|
|
00033e4af0 | ||
|
|
d327aea6ff | ||
|
|
12f44f3410 | ||
|
|
46d4bee8ab | ||
|
|
c288effa01 | ||
|
|
d9dd30f327 | ||
|
|
8b5b86fb4e | ||
|
|
4ddef92b80 | ||
|
|
543bd58ddd | ||
|
|
8d3271e586 | ||
|
|
2ba9904757 | ||
|
|
648651e2d7 |
49
.github/workflows/build.yml
vendored
49
.github/workflows/build.yml
vendored
@ -122,3 +122,52 @@ jobs:
|
||||
with:
|
||||
name: ${{ github.job }}-${{ matrix.arch }}
|
||||
path: ${{ github.job }}-${{ matrix.arch }}.tar.gz
|
||||
|
||||
# msvc:
|
||||
#
|
||||
# name: Visual Studio
|
||||
#
|
||||
# runs-on: windows-latest
|
||||
#
|
||||
# strategy:
|
||||
# fail-fast: false
|
||||
# matrix:
|
||||
# platform: [x86, x64]
|
||||
#
|
||||
# env:
|
||||
# CONFIGURATION: Release
|
||||
#
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
# - uses: msys2/setup-msys2@v2
|
||||
# with:
|
||||
# install: autoconf automake libtool pkg-config make gcc
|
||||
# - run: |
|
||||
# autoreconf --install --force
|
||||
# ./configure --prefix=/usr
|
||||
# make -C src revision.h
|
||||
# shell: msys2 {0}
|
||||
# - uses: microsoft/setup-msbuild@v1
|
||||
# - run: msbuild -m -p:Platform=${{ matrix.platform }} -p:Configuration=${{ env.CONFIGURATION }} contrib/msvc/libdivecomputer.vcxproj
|
||||
# - uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: ${{ github.job }}-${{ matrix.platform }}
|
||||
# path: contrib/msvc/${{ matrix.platform }}/${{ env.CONFIGURATION }}/bin
|
||||
|
||||
android:
|
||||
|
||||
name: Android
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: |
|
||||
autoreconf --install --force
|
||||
./configure --prefix=/usr
|
||||
make -C src revision.h
|
||||
- run: $ANDROID_NDK/ndk-build -C contrib/android NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ github.job }}
|
||||
path: contrib/android/libs
|
||||
|
||||
@ -16,5 +16,8 @@ pkgconfig_DATA = libdivecomputer.pc
|
||||
|
||||
EXTRA_DIST = \
|
||||
libdivecomputer.pc.in \
|
||||
msvc/libdivecomputer.vcxproj \
|
||||
msvc/libdivecomputer.vcxproj.filters
|
||||
contrib/README \
|
||||
contrib/android/Android.mk \
|
||||
contrib/msvc/libdivecomputer.vcxproj \
|
||||
contrib/msvc/libdivecomputer.vcxproj.filters \
|
||||
contrib/udev/libdivecomputer.rules
|
||||
|
||||
36
NEWS
36
NEWS
@ -1,4 +1,38 @@
|
||||
Version 0.7.0 (2020-05-07)
|
||||
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
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Versioning.
|
||||
m4_define([dc_version_major],[0])
|
||||
m4_define([dc_version_minor],[8])
|
||||
m4_define([dc_version_minor],[9])
|
||||
m4_define([dc_version_micro],[0])
|
||||
m4_define([dc_version_suffix],[devel-Subsurface-NG])
|
||||
m4_define([dc_version],dc_version_major.dc_version_minor.dc_version_micro[]m4_ifset([dc_version_suffix],-[dc_version_suffix]))
|
||||
@ -207,6 +207,8 @@ AX_APPEND_COMPILE_FLAGS([ \
|
||||
-Wno-unused-but-set-variable \
|
||||
-Wno-pointer-sign \
|
||||
-Wno-shadow \
|
||||
-Wenum-conversion \
|
||||
-Werror=enum-conversion \
|
||||
-fmacro-prefix-map='$(top_srcdir)/'= \
|
||||
],,[$ERROR_CFLAGS])
|
||||
|
||||
@ -253,7 +255,6 @@ AC_CONFIG_FILES([
|
||||
include/libdivecomputer/Makefile
|
||||
include/libdivecomputer/version.h
|
||||
src/Makefile
|
||||
src/libdivecomputer.rc
|
||||
doc/Makefile
|
||||
doc/doxygen.cfg
|
||||
doc/man/Makefile
|
||||
|
||||
56
contrib/README
Normal file
56
contrib/README
Normal file
@ -0,0 +1,56 @@
|
||||
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.
|
||||
148
contrib/android/Android.mk
Normal file
148
contrib/android/Android.mk
Normal file
@ -0,0 +1,148 @@
|
||||
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)
|
||||
408
contrib/msvc/libdivecomputer.vcxproj
Normal file
408
contrib/msvc/libdivecomputer.vcxproj
Normal file
@ -0,0 +1,408 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{CEA7215A-D6B5-4840-8086-3C854F371997}</ProjectGuid>
|
||||
<RootNamespace>libdivecomputer</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(PlatformTarget)\$(Configuration)\bin\</OutDir>
|
||||
<IntDir>$(PlatformTarget)\$(Configuration)\obj\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(PlatformTarget)\$(Configuration)\bin\</OutDir>
|
||||
<IntDir>$(PlatformTarget)\$(Configuration)\obj\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(PlatformTarget)\$(Configuration)\bin\</OutDir>
|
||||
<IntDir>$(PlatformTarget)\$(Configuration)\obj\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(PlatformTarget)\$(Configuration)\bin\</OutDir>
|
||||
<IntDir>$(PlatformTarget)\$(Configuration)\obj\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_VERSION_SUFFIX;HAVE_AF_IRDA_H;HAVE_WS2BTH_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader />
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>$(OutDir)libdivecomputer.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_VERSION_SUFFIX;HAVE_AF_IRDA_H;HAVE_WS2BTH_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>$(OutDir)libdivecomputer.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
</Link>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_VERSION_SUFFIX;HAVE_AF_IRDA_H;HAVE_WS2BTH_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader />
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>$(OutDir)libdivecomputer.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
</Link>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_VERSION_SUFFIX;HAVE_AF_IRDA_H;HAVE_WS2BTH_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<ModuleDefinitionFile>$(OutDir)libdivecomputer.def</ModuleDefinitionFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
</Link>
|
||||
<ResourceCompile>
|
||||
<AdditionalIncludeDirectories>..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ResourceCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\aes.c" />
|
||||
<ClCompile Include="..\..\src\array.c" />
|
||||
<ClCompile Include="..\..\src\atomics_cobalt.c" />
|
||||
<ClCompile Include="..\..\src\atomics_cobalt_parser.c" />
|
||||
<ClCompile Include="..\..\src\bluetooth.c" />
|
||||
<ClCompile Include="..\..\src\buffer.c" />
|
||||
<ClCompile Include="..\..\src\checksum.c" />
|
||||
<ClCompile Include="..\..\src\citizen_aqualand.c" />
|
||||
<ClCompile Include="..\..\src\citizen_aqualand_parser.c" />
|
||||
<ClCompile Include="..\..\src\cochran_commander.c" />
|
||||
<ClCompile Include="..\..\src\cochran_commander_parser.c" />
|
||||
<ClCompile Include="..\..\src\common.c" />
|
||||
<ClCompile Include="..\..\src\context.c" />
|
||||
<ClCompile Include="..\..\src\cressi_edy.c" />
|
||||
<ClCompile Include="..\..\src\cressi_edy_parser.c" />
|
||||
<ClCompile Include="..\..\src\cressi_goa.c" />
|
||||
<ClCompile Include="..\..\src\cressi_goa_parser.c" />
|
||||
<ClCompile Include="..\..\src\cressi_leonardo.c" />
|
||||
<ClCompile Include="..\..\src\cressi_leonardo_parser.c" />
|
||||
<ClCompile Include="..\..\src\custom.c" />
|
||||
<ClCompile Include="..\..\src\datetime.c" />
|
||||
<ClCompile Include="..\..\src\deepblu_cosmiq.c" />
|
||||
<ClCompile Include="..\..\src\deepblu_cosmiq_parser.c" />
|
||||
<ClCompile Include="..\..\src\deepsix_excursion.c" />
|
||||
<ClCompile Include="..\..\src\deepsix_excursion_parser.c" />
|
||||
<ClCompile Include="..\..\src\descriptor.c" />
|
||||
<ClCompile Include="..\..\src\device.c" />
|
||||
<ClCompile Include="..\..\src\diverite_nitekq.c" />
|
||||
<ClCompile Include="..\..\src\diverite_nitekq_parser.c" />
|
||||
<ClCompile Include="..\..\src\divesoft_freedom.c" />
|
||||
<ClCompile Include="..\..\src\divesoft_freedom_parser.c" />
|
||||
<ClCompile Include="..\..\src\divesystem_idive.c" />
|
||||
<ClCompile Include="..\..\src\divesystem_idive_parser.c" />
|
||||
<ClCompile Include="..\..\src\hdlc.c" />
|
||||
<ClCompile Include="..\..\src\hw_frog.c" />
|
||||
<ClCompile Include="..\..\src\hw_ostc.c" />
|
||||
<ClCompile Include="..\..\src\hw_ostc3.c" />
|
||||
<ClCompile Include="..\..\src\hw_ostc_parser.c" />
|
||||
<ClCompile Include="..\..\src\ihex.c" />
|
||||
<ClCompile Include="..\..\src\iostream.c" />
|
||||
<ClCompile Include="..\..\src\irda.c" />
|
||||
<ClCompile Include="..\..\src\iterator.c" />
|
||||
<ClCompile Include="..\..\src\liquivision_lynx.c" />
|
||||
<ClCompile Include="..\..\src\liquivision_lynx_parser.c" />
|
||||
<ClCompile Include="..\..\src\mares_common.c" />
|
||||
<ClCompile Include="..\..\src\mares_darwin.c" />
|
||||
<ClCompile Include="..\..\src\mares_darwin_parser.c" />
|
||||
<ClCompile Include="..\..\src\mares_iconhd.c" />
|
||||
<ClCompile Include="..\..\src\mares_iconhd_parser.c" />
|
||||
<ClCompile Include="..\..\src\mares_nemo.c" />
|
||||
<ClCompile Include="..\..\src\mares_nemo_parser.c" />
|
||||
<ClCompile Include="..\..\src\mares_puck.c" />
|
||||
<ClCompile Include="..\..\src\mclean_extreme.c" />
|
||||
<ClCompile Include="..\..\src\mclean_extreme_parser.c" />
|
||||
<ClCompile Include="..\..\src\oceanic_atom2.c" />
|
||||
<ClCompile Include="..\..\src\oceanic_atom2_parser.c" />
|
||||
<ClCompile Include="..\..\src\oceanic_common.c" />
|
||||
<ClCompile Include="..\..\src\oceanic_veo250.c" />
|
||||
<ClCompile Include="..\..\src\oceanic_veo250_parser.c" />
|
||||
<ClCompile Include="..\..\src\oceanic_vtpro.c" />
|
||||
<ClCompile Include="..\..\src\oceanic_vtpro_parser.c" />
|
||||
<ClCompile Include="..\..\src\oceans_s1.c" />
|
||||
<ClCompile Include="..\..\src\oceans_s1_common.c" />
|
||||
<ClCompile Include="..\..\src\oceans_s1_parser.c" />
|
||||
<ClCompile Include="..\..\src\packet.c" />
|
||||
<ClCompile Include="..\..\src\parser.c" />
|
||||
<ClCompile Include="..\..\src\pelagic_i330r.c" />
|
||||
<ClCompile Include="..\..\src\platform.c" />
|
||||
<ClCompile Include="..\..\src\rbstream.c" />
|
||||
<ClCompile Include="..\..\src\reefnet_sensus.c" />
|
||||
<ClCompile Include="..\..\src\reefnet_sensuspro.c" />
|
||||
<ClCompile Include="..\..\src\reefnet_sensuspro_parser.c" />
|
||||
<ClCompile Include="..\..\src\reefnet_sensusultra.c" />
|
||||
<ClCompile Include="..\..\src\reefnet_sensusultra_parser.c" />
|
||||
<ClCompile Include="..\..\src\reefnet_sensus_parser.c" />
|
||||
<ClCompile Include="..\..\src\ringbuffer.c" />
|
||||
<ClCompile Include="..\..\src\seac_screen.c" />
|
||||
<ClCompile Include="..\..\src\seac_screen_parser.c" />
|
||||
<ClCompile Include="..\..\src\serial_win32.c" />
|
||||
<ClCompile Include="..\..\src\shearwater_common.c" />
|
||||
<ClCompile Include="..\..\src\shearwater_petrel.c" />
|
||||
<ClCompile Include="..\..\src\shearwater_predator.c" />
|
||||
<ClCompile Include="..\..\src\shearwater_predator_parser.c" />
|
||||
<ClCompile Include="..\..\src\socket.c" />
|
||||
<ClCompile Include="..\..\src\sporasub_sp2.c" />
|
||||
<ClCompile Include="..\..\src\sporasub_sp2_parser.c" />
|
||||
<ClCompile Include="..\..\src\suunto_common.c" />
|
||||
<ClCompile Include="..\..\src\suunto_common2.c" />
|
||||
<ClCompile Include="..\..\src\suunto_d9.c" />
|
||||
<ClCompile Include="..\..\src\suunto_d9_parser.c" />
|
||||
<ClCompile Include="..\..\src\suunto_eon.c" />
|
||||
<ClCompile Include="..\..\src\suunto_eonsteel.c" />
|
||||
<ClCompile Include="..\..\src\suunto_eonsteel_parser.c" />
|
||||
<ClCompile Include="..\..\src\suunto_eon_parser.c" />
|
||||
<ClCompile Include="..\..\src\suunto_solution.c" />
|
||||
<ClCompile Include="..\..\src\suunto_solution_parser.c" />
|
||||
<ClCompile Include="..\..\src\suunto_vyper.c" />
|
||||
<ClCompile Include="..\..\src\suunto_vyper2.c" />
|
||||
<ClCompile Include="..\..\src\suunto_vyper_parser.c" />
|
||||
<ClCompile Include="..\..\src\tecdiving_divecomputereu.c" />
|
||||
<ClCompile Include="..\..\src\tecdiving_divecomputereu_parser.c" />
|
||||
<ClCompile Include="..\..\src\timer.c" />
|
||||
<ClCompile Include="..\..\src\usb.c" />
|
||||
<ClCompile Include="..\..\src\usbhid.c" />
|
||||
<ClCompile Include="..\..\src\uwatec_aladin.c" />
|
||||
<ClCompile Include="..\..\src\uwatec_memomouse.c" />
|
||||
<ClCompile Include="..\..\src\uwatec_memomouse_parser.c" />
|
||||
<ClCompile Include="..\..\src\uwatec_smart.c" />
|
||||
<ClCompile Include="..\..\src\uwatec_smart_parser.c" />
|
||||
<ClCompile Include="..\..\src\version.c" />
|
||||
<ClCompile Include="..\..\src\zeagle_n2ition3.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\include\libdivecomputer\atomics_cobalt.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\ble.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\bluetooth.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\buffer.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\common.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\context.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\custom.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\datetime.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\descriptor.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\device.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\divesystem_idive.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\hw_frog.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\hw_ostc.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\hw_ostc3.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\ioctl.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\iostream.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\irda.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\iterator.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\oceanic_atom2.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\oceanic_veo250.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\oceanic_vtpro.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\parser.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\reefnet_sensus.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\reefnet_sensuspro.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\reefnet_sensusultra.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\serial.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\suunto_d9.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\suunto_eon.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\suunto_vyper2.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\units.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\usb.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\usbhid.h" />
|
||||
<ClInclude Include="..\..\include\libdivecomputer\version.h" />
|
||||
<ClInclude Include="..\..\src\aes.h" />
|
||||
<ClInclude Include="..\..\src\array.h" />
|
||||
<ClInclude Include="..\..\src\atomics_cobalt.h" />
|
||||
<ClInclude Include="..\..\src\checksum.h" />
|
||||
<ClInclude Include="..\..\src\citizen_aqualand.h" />
|
||||
<ClInclude Include="..\..\src\cochran_commander.h" />
|
||||
<ClInclude Include="..\..\src\common-private.h" />
|
||||
<ClInclude Include="..\..\src\context-private.h" />
|
||||
<ClInclude Include="..\..\src\cressi_edy.h" />
|
||||
<ClInclude Include="..\..\src\cressi_goa.h" />
|
||||
<ClInclude Include="..\..\src\cressi_leonardo.h" />
|
||||
<ClInclude Include="..\..\src\deepblu_cosmiq.h" />
|
||||
<ClInclude Include="..\..\src\deepsix_excursion.h" />
|
||||
<ClInclude Include="..\..\src\device-private.h" />
|
||||
<ClInclude Include="..\..\src\diverite_nitekq.h" />
|
||||
<ClInclude Include="..\..\src\divesoft_freedom.h" />
|
||||
<ClInclude Include="..\..\src\divesystem_idive.h" />
|
||||
<ClInclude Include="..\..\src\hdlc.h" />
|
||||
<ClInclude Include="..\..\src\hw_frog.h" />
|
||||
<ClInclude Include="..\..\src\hw_ostc.h" />
|
||||
<ClInclude Include="..\..\src\hw_ostc3.h" />
|
||||
<ClInclude Include="..\..\src\ihex.h" />
|
||||
<ClInclude Include="..\..\src\iostream-private.h" />
|
||||
<ClInclude Include="..\..\src\iterator-private.h" />
|
||||
<ClInclude Include="..\..\src\liquivision_lynx.h" />
|
||||
<ClInclude Include="..\..\src\mares_common.h" />
|
||||
<ClInclude Include="..\..\src\mares_darwin.h" />
|
||||
<ClInclude Include="..\..\src\mares_iconhd.h" />
|
||||
<ClInclude Include="..\..\src\mares_nemo.h" />
|
||||
<ClInclude Include="..\..\src\mares_puck.h" />
|
||||
<ClInclude Include="..\..\src\mclean_extreme.h" />
|
||||
<ClInclude Include="..\..\src\oceanic_atom2.h" />
|
||||
<ClInclude Include="..\..\src\oceanic_common.h" />
|
||||
<ClInclude Include="..\..\src\oceanic_veo250.h" />
|
||||
<ClInclude Include="..\..\src\oceanic_vtpro.h" />
|
||||
<ClInclude Include="..\..\src\oceans_s1.h" />
|
||||
<ClInclude Include="..\..\src\oceans_s1_common.h" />
|
||||
<ClInclude Include="..\..\src\packet.h" />
|
||||
<ClInclude Include="..\..\src\parser-private.h" />
|
||||
<ClInclude Include="..\..\src\pelagic_i330r.h" />
|
||||
<ClInclude Include="..\..\src\platform.h" />
|
||||
<ClInclude Include="..\..\src\rbstream.h" />
|
||||
<ClInclude Include="..\..\src\reefnet_sensus.h" />
|
||||
<ClInclude Include="..\..\src\reefnet_sensuspro.h" />
|
||||
<ClInclude Include="..\..\src\reefnet_sensusultra.h" />
|
||||
<ClInclude Include="..\..\src\revision.h" />
|
||||
<ClInclude Include="..\..\src\ringbuffer.h" />
|
||||
<ClInclude Include="..\..\src\seac_screen.h" />
|
||||
<ClInclude Include="..\..\src\shearwater_common.h" />
|
||||
<ClInclude Include="..\..\src\shearwater_petrel.h" />
|
||||
<ClInclude Include="..\..\src\shearwater_predator.h" />
|
||||
<ClInclude Include="..\..\src\socket.h" />
|
||||
<ClInclude Include="..\..\src\sporasub_sp2.h" />
|
||||
<ClInclude Include="..\..\src\suunto_common.h" />
|
||||
<ClInclude Include="..\..\src\suunto_common2.h" />
|
||||
<ClInclude Include="..\..\src\suunto_d9.h" />
|
||||
<ClInclude Include="..\..\src\suunto_eon.h" />
|
||||
<ClInclude Include="..\..\src\suunto_eonsteel.h" />
|
||||
<ClInclude Include="..\..\src\suunto_solution.h" />
|
||||
<ClInclude Include="..\..\src\suunto_vyper.h" />
|
||||
<ClInclude Include="..\..\src\suunto_vyper2.h" />
|
||||
<ClInclude Include="..\..\src\tecdiving_divecomputereu.h" />
|
||||
<ClInclude Include="..\..\src\timer.h" />
|
||||
<ClInclude Include="..\..\src\uwatec_aladin.h" />
|
||||
<ClInclude Include="..\..\src\uwatec_memomouse.h" />
|
||||
<ClInclude Include="..\..\src\uwatec_smart.h" />
|
||||
<ClInclude Include="..\..\src\zeagle_n2ition3.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\..\src\libdivecomputer.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\src\libdivecomputer.symbols">
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">echo EXPORTS > "$(OutDir)libdivecomputer.def" && type "%(FullPath)" >> "$(OutDir)libdivecomputer.def"</Command>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">echo EXPORTS > "$(OutDir)libdivecomputer.def" && type "%(FullPath)" >> "$(OutDir)libdivecomputer.def"</Command>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)libdivecomputer.def;%(Outputs)</Outputs>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)libdivecomputer.def;%(Outputs)</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">echo EXPORTS > "$(OutDir)libdivecomputer.def" && type "%(FullPath)" >> "$(OutDir)libdivecomputer.def"</Command>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">echo EXPORTS > "$(OutDir)libdivecomputer.def" && type "%(FullPath)" >> "$(OutDir)libdivecomputer.def"</Command>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)libdivecomputer.def;%(Outputs)</Outputs>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)libdivecomputer.def;%(Outputs)</Outputs>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@ -32,7 +32,6 @@ MANPAGES = \
|
||||
dc_parser_get_field.3 \
|
||||
dc_parser_new.3 \
|
||||
dc_parser_samples_foreach.3 \
|
||||
dc_parser_set_data.3 \
|
||||
dc_bluetooth_open.3 \
|
||||
dc_bluetooth_iterator_new.3 \
|
||||
dc_bluetooth_device_get_address.3 \
|
||||
|
||||
@ -82,7 +82,7 @@ is
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_datetime_localtime 3 ,
|
||||
.Xr dc_datetime_mktime 3 ,
|
||||
.Xr dc_datetime_new 3
|
||||
.Xr dc_datetime_now 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -82,7 +82,7 @@ is
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_datetime_gmtime 3 ,
|
||||
.Xr dc_datetime_mktime 3 ,
|
||||
.Xr dc_datetime_new 3
|
||||
.Xr dc_datetime_now 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -47,7 +47,7 @@ may not sanely be converted.
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_datetime_gmtime 3 ,
|
||||
.Xr dc_datetime_localtime 3 ,
|
||||
.Xr dc_datetime_new 3
|
||||
.Xr dc_datetime_now 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -53,7 +53,7 @@ with
|
||||
Each dive invokes
|
||||
.Fa callback
|
||||
with the dive data, which should be parsed with
|
||||
.Xr dc_parser_set_data 3 ,
|
||||
.Xr dc_parser_new 3 ,
|
||||
and the binary fingerprint of the dive.
|
||||
The fingerprint can be used to record the newest dive and stop
|
||||
processing (on subsequent invocations) when the same dive fingerprint is
|
||||
@ -72,7 +72,7 @@ If
|
||||
returns zero, this will not be reflected in the return value (usually
|
||||
.Dv DC_STATUS_SUCCESS ) .
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_parser_set_data 3
|
||||
.Xr dc_parser_new 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
Extract the date and time of a dive,
|
||||
.Fa parser ,
|
||||
previously initialised with
|
||||
.Xr dc_parser_set_data 3 .
|
||||
.Xr dc_parser_new 3 .
|
||||
This returns the broken-down time-stamp of the dive in the local time of
|
||||
the dive.
|
||||
.Pp
|
||||
@ -57,7 +57,7 @@ messages on further failure.
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_datetime_gmtime 3 ,
|
||||
.Xr dc_datetime_localtime 3 ,
|
||||
.Xr dc_parser_set_data 3
|
||||
.Xr dc_parser_new 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
Extract a field from a dive,
|
||||
.Fa parser ,
|
||||
previously initialised with
|
||||
.Xr dc_parser_set_data 3 .
|
||||
.Xr dc_parser_new 3 .
|
||||
The
|
||||
.Fa value
|
||||
field type depends upon the
|
||||
@ -187,7 +187,7 @@ if the field was retrieved,
|
||||
if the field is not supported by the device, or other error messages on
|
||||
further failure.
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_parser_set_data 3
|
||||
.Xr dc_parser_new 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -39,8 +39,6 @@
|
||||
.Fa "dc_parser_t **parser"
|
||||
.Fa "dc_context_t *context"
|
||||
.Fa "dc_descriptor_t *descriptor"
|
||||
.Fa "unsigned int devtime"
|
||||
.Fa "dc_ticks_t systime"
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
Creates a parser for a single dive extracted from the dive computer with
|
||||
@ -55,10 +53,6 @@ parameter; and
|
||||
.Nm dc_parser_new2 ,
|
||||
which is given device values (model, etc.) directly.
|
||||
.Pp
|
||||
After filling in the
|
||||
.Fa parser
|
||||
parameter, one usually sets parser data with
|
||||
.Xr dc_parser_set_data 3 .
|
||||
The pointer must later be freed with
|
||||
.Xr dc_parser_destroy 3 .
|
||||
.Sh RETURN VALUES
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
.Ft "typedef void"
|
||||
.Fo "(*dc_sample_callback_t)"
|
||||
.Fa "dc_sample_type_t type"
|
||||
.Fa "dc_sample_value_t value"
|
||||
.Fa "const dc_sample_value_t *value"
|
||||
.Fa "void *userdata"
|
||||
.Fc
|
||||
.Ft dc_status_t
|
||||
@ -42,7 +42,7 @@
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
Extract the samples taken during a dive as previously initialised with
|
||||
.Xr dc_parser_set_data 3 .
|
||||
.Xr dc_parser_new 3 .
|
||||
Each sample is passed to
|
||||
.Fa callback
|
||||
with the
|
||||
@ -63,7 +63,7 @@ closed.
|
||||
The following sample types may be raised:
|
||||
.Bl -tag -width Ds
|
||||
.It Dv DC_SAMPLE_TIME
|
||||
The time of the sample taken in seconds after the dive began.
|
||||
The time of the sample taken in milliseconds after the dive began.
|
||||
Set in the
|
||||
.Fa time
|
||||
field.
|
||||
@ -184,7 +184,7 @@ Returns
|
||||
.Dv DC_STATUS_OK
|
||||
on success and another code on failure.
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_parser_set_data 3
|
||||
.Xr dc_parser_new 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
.\"
|
||||
.\" libdivecomputer
|
||||
.\"
|
||||
.\" Copyright (C) 2017 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
.\"
|
||||
.\" This library is free software; you can redistribute it and/or
|
||||
.\" modify it under the terms of the GNU Lesser General Public
|
||||
.\" License as published by the Free Software Foundation; either
|
||||
.\" version 2.1 of the License, or (at your option) any later version.
|
||||
.\"
|
||||
.\" This library is distributed in the hope that it will be useful,
|
||||
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
.\" Lesser General Public License for more details.
|
||||
.\"
|
||||
.\" You should have received a copy of the GNU Lesser General Public
|
||||
.\" License along with this library; if not, write to the Free Software
|
||||
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
.\" MA 02110-1301 USA
|
||||
.\"
|
||||
.Dd January 5, 2017
|
||||
.Dt DC_PARSER_SET_DATA 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm dc_parser_set_data
|
||||
.Nd assigns parse data to a dive parser
|
||||
.Sh LIBRARY
|
||||
.Lb libdivecomputer
|
||||
.Sh SYNOPSIS
|
||||
.In libdivecomputer/parser.h
|
||||
.Ft dc_status_t
|
||||
.Fo dc_parser_set_data
|
||||
.Fa "dc_parser_t *parser"
|
||||
.Fa "const unsigned char *data"
|
||||
.Fa "unsigned int size"
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
Assigns the binary sequence
|
||||
.Fa data
|
||||
of length
|
||||
.Fa size
|
||||
bytes to
|
||||
.Fa parser ,
|
||||
which was created with
|
||||
.Xr dc_parser_new 3 .
|
||||
How the data is parsed depends upon the values provided to
|
||||
.Xr dc_parser_new 3 .
|
||||
The data usually comes from the callback assigned to
|
||||
.Xr dc_device_foreach 3 .
|
||||
.Sh RETURN VALUES
|
||||
Returns
|
||||
.Dv DC_STATUS_OK
|
||||
on success and another code on failure.
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_device_foreach 3 ,
|
||||
.Xr dc_parser_new 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
library was written by
|
||||
.An Jef Driesen ,
|
||||
.Mt jef@libdivecomputer.org .
|
||||
The manpages were written by
|
||||
.An Kristaps Dzonsons ,
|
||||
.Mt kristaps@bsd.lv .
|
||||
@ -82,9 +82,7 @@ Iterate over all dives with
|
||||
.Xr dc_device_foreach 3 .
|
||||
.It
|
||||
For each iterated dive, create a new parser with
|
||||
.Xr dc_parser_new 3
|
||||
and set the parsed data with
|
||||
.Xr dc_parser_set_data 3 .
|
||||
.Xr dc_parser_new 3 .
|
||||
.It
|
||||
Get attributes of the parsed dive with
|
||||
.Xr dc_parser_get_field 3 .
|
||||
|
||||
@ -72,6 +72,7 @@ static const backend_table_t g_backends[] = {
|
||||
{"vtpro", DC_FAMILY_OCEANIC_VTPRO, 0x4245},
|
||||
{"veo250", DC_FAMILY_OCEANIC_VEO250, 0x424C},
|
||||
{"atom2", DC_FAMILY_OCEANIC_ATOM2, 0x4342},
|
||||
{"i330r", DC_FAMILY_PELAGIC_I330R, 0x4744},
|
||||
{"nemo", DC_FAMILY_MARES_NEMO, 0},
|
||||
{"puck", DC_FAMILY_MARES_PUCK, 7},
|
||||
{"darwin", DC_FAMILY_MARES_DARWIN, 0},
|
||||
@ -98,6 +99,7 @@ static const backend_table_t g_backends[] = {
|
||||
{"screen", DC_FAMILY_SEAC_SCREEN, 0},
|
||||
{"cosmiq", DC_FAMILY_DEEPBLU_COSMIQ, 0},
|
||||
{"s1", DC_FAMILY_OCEANS_S1, 0},
|
||||
{"freedom", DC_FAMILY_DIVESOFT_FREEDOM, 19},
|
||||
|
||||
// Not merged upstream yet
|
||||
{"descentmk1", DC_FAMILY_GARMIN, 0},
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
#define RESET 1
|
||||
#endif
|
||||
|
||||
#if defined(__GLIBC__) || defined(__MINGW32__) || defined(BSD)
|
||||
#if defined(__GLIBC__) || defined(__MINGW32__) || defined(BSD) || defined(__ANDROID__)
|
||||
#define NOPERMUTATION "+"
|
||||
#else
|
||||
#define NOPERMUTATION ""
|
||||
|
||||
@ -80,20 +80,12 @@ dive_cb (const unsigned char *data, unsigned int size, const unsigned char *fing
|
||||
|
||||
// Create the parser.
|
||||
message ("Creating the parser.\n");
|
||||
rc = dc_parser_new (&parser, divedata->device);
|
||||
rc = dc_parser_new (&parser, divedata->device, data, size);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR ("Error creating the parser.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Register the data.
|
||||
message ("Registering the data.\n");
|
||||
rc = dc_parser_set_data (parser, data, size);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR ("Error registering the data.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Parse the dive data.
|
||||
message ("Parsing the dive data.\n");
|
||||
rc = dctool_output_write (divedata->output, parser, data, size, fingerprint, fsize);
|
||||
|
||||
@ -94,7 +94,7 @@ fwupdate (dc_context_t *context, dc_descriptor_t *descriptor, dc_transport_t tra
|
||||
rc = hw_ostc_device_fwupdate (device, hexfile);
|
||||
break;
|
||||
case DC_FAMILY_HW_OSTC3:
|
||||
rc = hw_ostc3_device_fwupdate (device, hexfile);
|
||||
rc = hw_ostc3_device_fwupdate (device, hexfile, false);
|
||||
break;
|
||||
case DC_FAMILY_DIVESYSTEM_IDIVE:
|
||||
rc = divesystem_idive_device_fwupdate (device, hexfile);
|
||||
|
||||
@ -54,17 +54,17 @@ parse (dc_buffer_t *buffer, dc_context_t *context, dc_descriptor_t *descriptor,
|
||||
|
||||
// Create the parser.
|
||||
message ("Creating the parser.\n");
|
||||
rc = dc_parser_new2 (&parser, context, descriptor, devtime, systime);
|
||||
rc = dc_parser_new2 (&parser, context, descriptor, data, size);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR ("Error creating the parser.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Register the data.
|
||||
message ("Registering the data.\n");
|
||||
rc = dc_parser_set_data (parser, data, size);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR ("Error registering the data.");
|
||||
// Set the clock.
|
||||
message ("Setting the clock.\n");
|
||||
rc = dc_parser_set_clock (parser, devtime, systime);
|
||||
if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
|
||||
ERROR ("Error setting the clock.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
@ -90,7 +90,7 @@ convert_volume (double value, dctool_units_t units)
|
||||
}
|
||||
|
||||
static void
|
||||
sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata)
|
||||
sample_cb (dc_sample_type_t type, const dc_sample_value_t *value, void *userdata)
|
||||
{
|
||||
static const char *events[] = {
|
||||
"none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter",
|
||||
@ -104,64 +104,80 @@ sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata)
|
||||
|
||||
sample_data_t *sampledata = (sample_data_t *) userdata;
|
||||
|
||||
unsigned int seconds = 0, milliseconds = 0;
|
||||
|
||||
switch (type) {
|
||||
case DC_SAMPLE_TIME:
|
||||
seconds = value->time / 1000;
|
||||
milliseconds = value->time % 1000;
|
||||
if (sampledata->nsamples++)
|
||||
fprintf (sampledata->ostream, "</sample>\n");
|
||||
fprintf (sampledata->ostream, "<sample>\n");
|
||||
fprintf (sampledata->ostream, " <time>%02u:%02u</time>\n", value.time / 60, value.time % 60);
|
||||
if (milliseconds) {
|
||||
fprintf (sampledata->ostream, " <time>%02u:%02u.%03u</time>\n", seconds / 60, seconds % 60, milliseconds);
|
||||
} else {
|
||||
fprintf (sampledata->ostream, " <time>%02u:%02u</time>\n", seconds / 60, seconds % 60);
|
||||
}
|
||||
break;
|
||||
case DC_SAMPLE_DEPTH:
|
||||
fprintf (sampledata->ostream, " <depth>%.2f</depth>\n",
|
||||
convert_depth(value.depth, sampledata->units));
|
||||
convert_depth(value->depth, sampledata->units));
|
||||
break;
|
||||
case DC_SAMPLE_PRESSURE:
|
||||
fprintf (sampledata->ostream, " <pressure tank=\"%u\">%.2f</pressure>\n",
|
||||
value.pressure.tank,
|
||||
convert_pressure(value.pressure.value, sampledata->units));
|
||||
value->pressure.tank,
|
||||
convert_pressure(value->pressure.value, sampledata->units));
|
||||
break;
|
||||
case DC_SAMPLE_TEMPERATURE:
|
||||
fprintf (sampledata->ostream, " <temperature>%.2f</temperature>\n",
|
||||
convert_temperature(value.temperature, sampledata->units));
|
||||
convert_temperature(value->temperature, sampledata->units));
|
||||
break;
|
||||
case DC_SAMPLE_EVENT:
|
||||
if (value.event.type != SAMPLE_EVENT_GASCHANGE && value.event.type != SAMPLE_EVENT_GASCHANGE2) {
|
||||
if (value->event.type != SAMPLE_EVENT_GASCHANGE && value->event.type != SAMPLE_EVENT_GASCHANGE2) {
|
||||
fprintf (sampledata->ostream, " <event type=\"%u\" time=\"%u\" flags=\"%u\" value=\"%u\">%s</event>\n",
|
||||
value.event.type, value.event.time, value.event.flags, value.event.value, events[value.event.type]);
|
||||
value->event.type, value->event.time, value->event.flags, value->event.value, events[value->event.type]);
|
||||
}
|
||||
break;
|
||||
case DC_SAMPLE_RBT:
|
||||
fprintf (sampledata->ostream, " <rbt>%u</rbt>\n", value.rbt);
|
||||
fprintf (sampledata->ostream, " <rbt>%u</rbt>\n", value->rbt);
|
||||
break;
|
||||
case DC_SAMPLE_HEARTBEAT:
|
||||
fprintf (sampledata->ostream, " <heartbeat>%u</heartbeat>\n", value.heartbeat);
|
||||
fprintf (sampledata->ostream, " <heartbeat>%u</heartbeat>\n", value->heartbeat);
|
||||
break;
|
||||
case DC_SAMPLE_BEARING:
|
||||
fprintf (sampledata->ostream, " <bearing>%u</bearing>\n", value.bearing);
|
||||
fprintf (sampledata->ostream, " <bearing>%u</bearing>\n", value->bearing);
|
||||
break;
|
||||
case DC_SAMPLE_VENDOR:
|
||||
fprintf (sampledata->ostream, " <vendor type=\"%u\" size=\"%u\">", value.vendor.type, value.vendor.size);
|
||||
for (unsigned int i = 0; i < value.vendor.size; ++i)
|
||||
fprintf (sampledata->ostream, "%02X", ((const unsigned char *) value.vendor.data)[i]);
|
||||
fprintf (sampledata->ostream, " <vendor type=\"%u\" size=\"%u\">", value->vendor.type, value->vendor.size);
|
||||
for (unsigned int i = 0; i < value->vendor.size; ++i)
|
||||
fprintf (sampledata->ostream, "%02X", ((const unsigned char *) value->vendor.data)[i]);
|
||||
fprintf (sampledata->ostream, "</vendor>\n");
|
||||
break;
|
||||
case DC_SAMPLE_SETPOINT:
|
||||
fprintf (sampledata->ostream, " <setpoint>%.2f</setpoint>\n", value.setpoint);
|
||||
fprintf (sampledata->ostream, " <setpoint>%.2f</setpoint>\n", value->setpoint);
|
||||
break;
|
||||
case DC_SAMPLE_PPO2:
|
||||
fprintf (sampledata->ostream, " <ppo2>%.2f</ppo2>\n", value.ppo2);
|
||||
if (value->ppo2.sensor != DC_SENSOR_NONE) {
|
||||
fprintf (sampledata->ostream, " <ppo2 sensor=\"%u\">%.2f</ppo2>\n", value->ppo2.sensor, value->ppo2.value);
|
||||
} else {
|
||||
fprintf (sampledata->ostream, " <ppo2>%.2f</ppo2>\n", value->ppo2.value);
|
||||
}
|
||||
break;
|
||||
case DC_SAMPLE_CNS:
|
||||
fprintf (sampledata->ostream, " <cns>%.1f</cns>\n", value.cns * 100.0);
|
||||
fprintf (sampledata->ostream, " <cns>%.1f</cns>\n", value->cns * 100.0);
|
||||
break;
|
||||
case DC_SAMPLE_DECO:
|
||||
fprintf (sampledata->ostream, " <deco time=\"%u\" depth=\"%.2f\">%s</deco>\n",
|
||||
value.deco.time,
|
||||
convert_depth(value.deco.depth, sampledata->units),
|
||||
decostop[value.deco.type]);
|
||||
value->deco.time,
|
||||
convert_depth(value->deco.depth, sampledata->units),
|
||||
decostop[value->deco.type]);
|
||||
if (value->deco.tts) {
|
||||
fprintf (sampledata->ostream, " <tts>%u</tts>\n",
|
||||
value->deco.tts);
|
||||
}
|
||||
break;
|
||||
case DC_SAMPLE_GASMIX:
|
||||
fprintf (sampledata->ostream, " <gasmix>%u</gasmix>\n", value.gasmix);
|
||||
fprintf (sampledata->ostream, " <gasmix>%u</gasmix>\n", value->gasmix);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -322,11 +338,19 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
||||
"<gasmix>\n"
|
||||
" <he>%.1f</he>\n"
|
||||
" <o2>%.1f</o2>\n"
|
||||
" <n2>%.1f</n2>\n"
|
||||
"</gasmix>\n",
|
||||
" <n2>%.1f</n2>\n",
|
||||
gasmix.helium * 100.0,
|
||||
gasmix.oxygen * 100.0,
|
||||
gasmix.nitrogen * 100.0);
|
||||
if (gasmix.usage) {
|
||||
const char *usage[] = {"none", "oxygen", "diluent", "sidemount"};
|
||||
fprintf (output->ostream,
|
||||
" <usage>%s</usage>\n",
|
||||
usage[gasmix.usage]);
|
||||
}
|
||||
fprintf (output->ostream,
|
||||
"</gasmix>\n");
|
||||
|
||||
}
|
||||
|
||||
// Parse the tanks.
|
||||
@ -354,6 +378,12 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
||||
" <gasmix>%u</gasmix>\n",
|
||||
tank.gasmix);
|
||||
}
|
||||
if (tank.usage) {
|
||||
const char *usage[] = {"none", "oxygen", "diluent", "sidemount"};
|
||||
fprintf (output->ostream,
|
||||
" <usage>%s</usage>\n",
|
||||
usage[tank.usage]);
|
||||
}
|
||||
if (tank.type != DC_TANKVOLUME_NONE) {
|
||||
fprintf (output->ostream,
|
||||
" <type>%s</type>\n"
|
||||
@ -420,8 +450,14 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
||||
}
|
||||
|
||||
if (status != DC_STATUS_UNSUPPORTED) {
|
||||
fprintf (output->ostream, "<salinity type=\"%u\">%.1f</salinity>\n",
|
||||
salinity.type, salinity.density);
|
||||
const char *names[] = {"fresh", "salt"};
|
||||
if (salinity.density) {
|
||||
fprintf (output->ostream, "<salinity density=\"%.1f\">%s</salinity>\n",
|
||||
salinity.density, names[salinity.type]);
|
||||
} else {
|
||||
fprintf (output->ostream, "<salinity>%s</salinity>\n",
|
||||
names[salinity.type]);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the atmospheric pressure.
|
||||
|
||||
@ -36,9 +36,6 @@ atomics_cobalt_device_version (dc_device_t *device, unsigned char data[], unsign
|
||||
dc_status_t
|
||||
atomics_cobalt_device_set_simulation (dc_device_t *device, unsigned int simulation);
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -33,6 +33,21 @@ extern "C" {
|
||||
*/
|
||||
#define DC_IOCTL_BLE_GET_NAME DC_IOCTL_IOR('b', 0, DC_IOCTL_SIZE_VARIABLE)
|
||||
|
||||
/**
|
||||
* Get the bluetooth authentication PIN code.
|
||||
*
|
||||
* The data format is a NULL terminated string.
|
||||
*/
|
||||
#define DC_IOCTL_BLE_GET_PINCODE DC_IOCTL_IOR('b', 1, DC_IOCTL_SIZE_VARIABLE)
|
||||
|
||||
/**
|
||||
* Get/set the bluetooth authentication access code.
|
||||
*
|
||||
* The data format is a variable sized byte array.
|
||||
*/
|
||||
#define DC_IOCTL_BLE_GET_ACCESSCODE DC_IOCTL_IOR('b', 2, DC_IOCTL_SIZE_VARIABLE)
|
||||
#define DC_IOCTL_BLE_SET_ACCESSCODE DC_IOCTL_IOW('b', 2, DC_IOCTL_SIZE_VARIABLE)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -78,6 +78,7 @@ typedef enum dc_family_t {
|
||||
DC_FAMILY_OCEANIC_VTPRO = (4 << 16),
|
||||
DC_FAMILY_OCEANIC_VEO250,
|
||||
DC_FAMILY_OCEANIC_ATOM2,
|
||||
DC_FAMILY_PELAGIC_I330R,
|
||||
/* Mares */
|
||||
DC_FAMILY_MARES_NEMO = (5 << 16),
|
||||
DC_FAMILY_MARES_PUCK,
|
||||
@ -122,6 +123,8 @@ typedef enum dc_family_t {
|
||||
DC_FAMILY_DEEPBLU_COSMIQ = (21 << 16),
|
||||
/* Oceans S1 */
|
||||
DC_FAMILY_OCEANS_S1 = (22 << 16),
|
||||
/* Divesoft Freedom */
|
||||
DC_FAMILY_DIVESOFT_FREEDOM = (23 << 16),
|
||||
|
||||
// Not merged upstream yet
|
||||
/* Garmin */
|
||||
|
||||
@ -29,29 +29,96 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* Opaque object representing a supported dive computer.
|
||||
*/
|
||||
typedef struct dc_descriptor_t dc_descriptor_t;
|
||||
|
||||
/**
|
||||
* Create an iterator to enumerate the supported dive computers.
|
||||
*
|
||||
* @param[out] iterator A location to store the iterator.
|
||||
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
|
||||
* on failure.
|
||||
*/
|
||||
dc_status_t
|
||||
dc_descriptor_iterator (dc_iterator_t **iterator);
|
||||
|
||||
/**
|
||||
* Free the device descriptor.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
*/
|
||||
void
|
||||
dc_descriptor_free (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Get the vendor name of the dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @returns The vendor name of the dive computer on success, or NULL on failure.
|
||||
*/
|
||||
const char *
|
||||
dc_descriptor_get_vendor (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Get the product name of the dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @returns The product name of the dive computer on success, or NULL on
|
||||
* failure.
|
||||
*/
|
||||
const char *
|
||||
dc_descriptor_get_product (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Get the family type of the dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @returns The family type of the dive computer on success, or DC_FAMILY_NULL
|
||||
* on failure.
|
||||
*/
|
||||
dc_family_t
|
||||
dc_descriptor_get_type (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Get the model number of the dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @returns The model number of the dive computer on success, or zero on
|
||||
* failure.
|
||||
*/
|
||||
unsigned int
|
||||
dc_descriptor_get_model (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Get all transports supported by the dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @returns A bitmask with all the transports supported by the dive computer on
|
||||
* success, or DC_TRANSPORT_NONE on failure.
|
||||
*/
|
||||
unsigned int
|
||||
dc_descriptor_get_transports (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Check if a low-level I/O device matches a supported dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @param[in] transport The transport type of the I/O device.
|
||||
* @param[in] userdata A pointer to a transport specific data structure:
|
||||
* - DC_TRANSPORT_SERIAL: Name of the device node (string)
|
||||
* - DC_TRANSPORT_USB: USB VID/PID (#dc_usb_desc_t)
|
||||
* - DC_TRANSPORT_USBHID: USB VID/PID (#dc_usbhid_desc_t)
|
||||
* - DC_TRANSPORT_IRDA: IrDA device name (string)
|
||||
* - DC_TRANSPORT_BLUETOOTH: Bluetooth device name (string)
|
||||
* - DC_TRANSPORT_BLE: Bluetooth device name (string)
|
||||
* @returns Non-zero if the device matches a supported dive computer, or zero if
|
||||
* there is no match.
|
||||
*/
|
||||
int
|
||||
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -22,6 +22,8 @@
|
||||
#ifndef DC_HW_OSTC3_H
|
||||
#define DC_HW_OSTC3_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "device.h"
|
||||
#include "datetime.h"
|
||||
@ -55,7 +57,7 @@ dc_status_t
|
||||
hw_ostc3_device_config_reset (dc_device_t *abstract);
|
||||
|
||||
dc_status_t
|
||||
hw_ostc3_device_fwupdate (dc_device_t *abstract, const char *filename);
|
||||
hw_ostc3_device_fwupdate (dc_device_t *abstract, const char *filename, bool forceUpdate);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -173,19 +173,26 @@ typedef struct dc_salinity_t {
|
||||
double density;
|
||||
} dc_salinity_t;
|
||||
|
||||
typedef enum dc_usage_t {
|
||||
DC_USAGE_NONE, // Usage not specified
|
||||
DC_USAGE_OXYGEN,
|
||||
DC_USAGE_DILUENT,
|
||||
DC_USAGE_OPEN_CIRCUIT,
|
||||
} dc_usage_t;
|
||||
|
||||
typedef struct dc_gasmix_t {
|
||||
double helium;
|
||||
double oxygen;
|
||||
double nitrogen;
|
||||
dc_usage_t usage;
|
||||
} dc_gasmix_t;
|
||||
|
||||
#define DC_SENSOR_NONE 0xFFFFFFFF
|
||||
#define DC_GASMIX_UNKNOWN 0xFFFFFFFF
|
||||
|
||||
typedef unsigned int dc_tankinfo_t;
|
||||
#define DC_TANKINFO_METRIC 1
|
||||
#define DC_TANKINFO_IMPERIAL 2
|
||||
#define DC_TANKINFO_CC_DILUENT 4
|
||||
#define DC_TANKINFO_CC_O2 8
|
||||
|
||||
// For backwards compatibility
|
||||
#define DC_TANKVOLUME_NONE 0
|
||||
@ -215,6 +222,11 @@ typedef unsigned int dc_tankinfo_t;
|
||||
* divide by 1 ATM (Vair = Vwater * Pwork / Patm).
|
||||
*/
|
||||
|
||||
typedef enum dc_tank_usage_t {
|
||||
DC_TANK_USAGE_NONE,
|
||||
DC_TANK_USAGE_SIDEMOUNT,
|
||||
} dc_tank_usage_t;
|
||||
|
||||
typedef struct dc_tank_t {
|
||||
unsigned int gasmix; /* Gas mix index, or DC_GASMIX_UNKNOWN */
|
||||
dc_tankinfo_t type; /* Tank type - metric/imperial and oc/cc */
|
||||
@ -222,6 +234,7 @@ typedef struct dc_tank_t {
|
||||
double workpressure; /* Work pressure (bar) */
|
||||
double beginpressure; /* Begin pressure (bar) */
|
||||
double endpressure; /* End pressure (bar) */
|
||||
dc_tank_usage_t usage;
|
||||
} dc_tank_t;
|
||||
|
||||
typedef enum dc_decomodel_type_t {
|
||||
@ -267,7 +280,7 @@ typedef struct dc_field_string_t {
|
||||
} dc_field_string_t;
|
||||
|
||||
typedef union dc_sample_value_t {
|
||||
unsigned int time;
|
||||
unsigned int time; /* Milliseconds */
|
||||
double depth;
|
||||
struct {
|
||||
unsigned int tank;
|
||||
@ -290,25 +303,29 @@ typedef union dc_sample_value_t {
|
||||
const void *data;
|
||||
} vendor;
|
||||
double setpoint;
|
||||
double ppo2;
|
||||
struct {
|
||||
unsigned int sensor;
|
||||
double value;
|
||||
} ppo2;
|
||||
double cns;
|
||||
struct {
|
||||
unsigned int type;
|
||||
unsigned int time;
|
||||
double depth;
|
||||
unsigned int tts;
|
||||
} deco;
|
||||
unsigned int gasmix; /* Gas mix index */
|
||||
} dc_sample_value_t;
|
||||
|
||||
typedef struct dc_parser_t dc_parser_t;
|
||||
|
||||
typedef void (*dc_sample_callback_t) (dc_sample_type_t type, dc_sample_value_t value, void *userdata);
|
||||
typedef void (*dc_sample_callback_t) (dc_sample_type_t type, const dc_sample_value_t *value, void *userdata);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_new (dc_parser_t **parser, dc_device_t *device);
|
||||
dc_parser_new (dc_parser_t **parser, dc_device_t *device, const unsigned char data[], size_t size);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_new2 (dc_parser_t **parser, dc_context_t *context, dc_descriptor_t *descriptor, unsigned int devtime, dc_ticks_t systime);
|
||||
dc_parser_new2 (dc_parser_t **parser, dc_context_t *context, dc_descriptor_t *descriptor, const unsigned char data[], size_t size);
|
||||
|
||||
dc_family_t
|
||||
dc_parser_get_type (dc_parser_t *parser);
|
||||
@ -322,9 +339,6 @@ 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_parser_set_data (dc_parser_t *parser, const unsigned char *data, unsigned int size);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime);
|
||||
|
||||
|
||||
@ -35,9 +35,6 @@ extern "C" {
|
||||
dc_status_t
|
||||
reefnet_sensus_device_get_handshake (dc_device_t *device, unsigned char data[], unsigned int size);
|
||||
|
||||
dc_status_t
|
||||
reefnet_sensus_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -38,9 +38,6 @@ reefnet_sensuspro_device_get_handshake (dc_device_t *device, unsigned char data[
|
||||
dc_status_t
|
||||
reefnet_sensuspro_device_write_interval (dc_device_t *device, unsigned char interval);
|
||||
|
||||
dc_status_t
|
||||
reefnet_sensuspro_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -56,9 +56,6 @@ reefnet_sensusultra_device_write_parameter (dc_device_t *device, reefnet_sensusu
|
||||
dc_status_t
|
||||
reefnet_sensusultra_device_sense (dc_device_t *device, unsigned char data[], unsigned int size);
|
||||
|
||||
dc_status_t
|
||||
reefnet_sensusultra_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -86,6 +86,14 @@ typedef enum dc_usb_recipient_t {
|
||||
DC_USB_RECIPIENT_OTHER = 0x03,
|
||||
} dc_usb_recipient_t;
|
||||
|
||||
/**
|
||||
* USB device descriptor.
|
||||
*/
|
||||
typedef struct dc_usb_desc_t {
|
||||
unsigned short vid;
|
||||
unsigned short pid;
|
||||
} dc_usb_desc_t;
|
||||
|
||||
/**
|
||||
* Opaque object representing a USB device.
|
||||
*/
|
||||
|
||||
@ -32,6 +32,14 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* USB HID device descriptor.
|
||||
*/
|
||||
typedef struct dc_usbhid_desc_t {
|
||||
unsigned short vid;
|
||||
unsigned short pid;
|
||||
} dc_usbhid_desc_t;
|
||||
|
||||
/**
|
||||
* Opaque object representing a USB HID device.
|
||||
*/
|
||||
|
||||
@ -1,388 +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_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>
|
||||
</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_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>
|
||||
</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_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>
|
||||
</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_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>
|
||||
</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\divesystem_idive.c" />
|
||||
<ClCompile Include="..\src\divesystem_idive_parser.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\parser.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\descriptor-private.h" />
|
||||
<ClInclude Include="..\src\device-private.h" />
|
||||
<ClInclude Include="..\src\diverite_nitekq.h" />
|
||||
<ClInclude Include="..\src\divesystem_idive.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\parser-private.h" />
|
||||
<ClInclude Include="..\src\platform.h" />
|
||||
<ClInclude Include="..\src\rbstream.h" />
|
||||
<ClInclude Include="..\src\reefnet_sensus.h" />
|
||||
<ClInclude Include="..\src\reefnet_sensuspro.h" />
|
||||
<ClInclude Include="..\src\reefnet_sensusultra.h" />
|
||||
<ClInclude Include="..\src\revision.h" />
|
||||
<ClInclude Include="..\src\ringbuffer.h" />
|
||||
<ClInclude Include="..\src\seac_screen.h" />
|
||||
<ClInclude Include="..\src\shearwater_common.h" />
|
||||
<ClInclude Include="..\src\shearwater_petrel.h" />
|
||||
<ClInclude Include="..\src\shearwater_predator.h" />
|
||||
<ClInclude Include="..\src\socket.h" />
|
||||
<ClInclude Include="..\src\sporasub_sp2.h" />
|
||||
<ClInclude Include="..\src\suunto_common.h" />
|
||||
<ClInclude Include="..\src\suunto_common2.h" />
|
||||
<ClInclude Include="..\src\suunto_d9.h" />
|
||||
<ClInclude Include="..\src\suunto_eon.h" />
|
||||
<ClInclude Include="..\src\suunto_eonsteel.h" />
|
||||
<ClInclude Include="..\src\suunto_solution.h" />
|
||||
<ClInclude Include="..\src\suunto_vyper.h" />
|
||||
<ClInclude Include="..\src\suunto_vyper2.h" />
|
||||
<ClInclude Include="..\src\tecdiving_divecomputereu.h" />
|
||||
<ClInclude Include="..\src\timer.h" />
|
||||
<ClInclude Include="..\src\uwatec_aladin.h" />
|
||||
<ClInclude Include="..\src\uwatec_memomouse.h" />
|
||||
<ClInclude Include="..\src\uwatec_smart.h" />
|
||||
<ClInclude Include="..\src\zeagle_n2ition3.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="..\src\libdivecomputer.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\src\libdivecomputer.symbols">
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">echo EXPORTS > "$(OutDir)libdivecomputer.def" && type "%(FullPath)" >> "$(OutDir)libdivecomputer.def"</Command>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">echo EXPORTS > "$(OutDir)libdivecomputer.def" && type "%(FullPath)" >> "$(OutDir)libdivecomputer.def"</Command>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(OutDir)libdivecomputer.def;%(Outputs)</Outputs>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(OutDir)libdivecomputer.def;%(Outputs)</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">echo EXPORTS > "$(OutDir)libdivecomputer.def" && type "%(FullPath)" >> "$(OutDir)libdivecomputer.def"</Command>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">echo EXPORTS > "$(OutDir)libdivecomputer.def" && type "%(FullPath)" >> "$(OutDir)libdivecomputer.def"</Command>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(OutDir)libdivecomputer.def;%(Outputs)</Outputs>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(OutDir)libdivecomputer.def;%(Outputs)</Outputs>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@ -16,7 +16,7 @@ endif
|
||||
|
||||
libdivecomputer_la_SOURCES = \
|
||||
version.c \
|
||||
descriptor-private.h descriptor.c \
|
||||
descriptor.c \
|
||||
iostream-private.h iostream.c \
|
||||
iterator-private.h iterator.c \
|
||||
common-private.h common.c \
|
||||
@ -43,6 +43,7 @@ libdivecomputer_la_SOURCES = \
|
||||
oceanic_atom2.h oceanic_atom2.c oceanic_atom2_parser.c \
|
||||
oceanic_veo250.h oceanic_veo250.c oceanic_veo250_parser.c \
|
||||
oceanic_vtpro.h oceanic_vtpro.c oceanic_vtpro_parser.c \
|
||||
pelagic_i330r.h pelagic_i330r.c \
|
||||
mares_common.h mares_common.c \
|
||||
mares_nemo.h mares_nemo.c mares_nemo_parser.c \
|
||||
mares_puck.h mares_puck.c \
|
||||
@ -80,6 +81,9 @@ libdivecomputer_la_SOURCES = \
|
||||
deepblu_cosmiq.h deepblu_cosmiq.c deepblu_cosmiq_parser.c \
|
||||
oceans_s1_common.h oceans_s1_common.c \
|
||||
oceans_s1.h oceans_s1.c oceans_s1_parser.c \
|
||||
divesoft_freedom.h divesoft_freedom.c divesoft_freedom_parser.c \
|
||||
hdlc.h hdlc.c \
|
||||
packet.h packet.c \
|
||||
socket.h socket.c \
|
||||
irda.c \
|
||||
usb.c \
|
||||
@ -109,7 +113,7 @@ libdivecomputer.exp: libdivecomputer.symbols
|
||||
$(AM_V_GEN) sed -e '/^$$/d' $< > $@
|
||||
|
||||
.rc.lo:
|
||||
$(AM_V_GEN) $(LIBTOOL) --silent --tag=CC --mode=compile $(RC) $(DEFS) $(DEFAULT_INCLUDES) $< -o $@
|
||||
$(AM_V_GEN) $(LIBTOOL) --silent --tag=CC --mode=compile $(RC) $(DEFS) $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $< -o $@
|
||||
|
||||
libdivecomputer.lo: revision.h
|
||||
|
||||
|
||||
31
src/array.c
31
src/array.c
@ -384,3 +384,34 @@ dec2bcd (unsigned char value)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -123,6 +123,12 @@ bcd2dec (unsigned char value);
|
||||
unsigned char
|
||||
dec2bcd (unsigned char value);
|
||||
|
||||
unsigned int
|
||||
signextend (unsigned int value, unsigned int nbits);
|
||||
|
||||
unsigned int
|
||||
popcount (unsigned int value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -41,6 +41,8 @@
|
||||
|
||||
#define FP_OFFSET 20
|
||||
|
||||
#define SZ_HEADER 228
|
||||
|
||||
#define SZ_MEMORY1 (29 * 64 * 1024) // Cobalt 1
|
||||
#define SZ_MEMORY2 (41 * 64 * 1024) // Cobalt 2
|
||||
#define SZ_VERSION 14
|
||||
@ -347,6 +349,12 @@ atomics_cobalt_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (size < SZ_HEADER) {
|
||||
ERROR (abstract->context, "Dive header is too small (%u).", size);
|
||||
dc_buffer_free (buffer);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
if (memcmp (data + FP_OFFSET, device->fingerprint, sizeof (device->fingerprint)) == 0) {
|
||||
dc_buffer_free (buffer);
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
atomics_cobalt_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
atomics_cobalt_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -49,7 +49,6 @@ struct atomics_cobalt_parser_t {
|
||||
double hydrostatic;
|
||||
};
|
||||
|
||||
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_set_density (dc_parser_t *abstract, double density);
|
||||
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);
|
||||
@ -58,7 +57,6 @@ static dc_status_t atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract,
|
||||
static const dc_parser_vtable_t atomics_cobalt_parser_vtable = {
|
||||
sizeof(atomics_cobalt_parser_t),
|
||||
DC_FAMILY_ATOMICS_COBALT,
|
||||
atomics_cobalt_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
atomics_cobalt_parser_set_density, /* set_density */
|
||||
@ -70,7 +68,7 @@ static const dc_parser_vtable_t atomics_cobalt_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
atomics_cobalt_parser_t *parser = NULL;
|
||||
|
||||
@ -78,7 +76,7 @@ atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (atomics_cobalt_parser_t *) dc_parser_allocate (context, &atomics_cobalt_parser_vtable);
|
||||
parser = (atomics_cobalt_parser_t *) dc_parser_allocate (context, &atomics_cobalt_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -93,27 +91,6 @@ atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
atomics_cobalt_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
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->hydrostatic = hydrostatic;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
atomics_cobalt_parser_set_density (dc_parser_t *abstract, double density)
|
||||
{
|
||||
@ -182,6 +159,7 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
*((unsigned int *) value) = p[0x2a];
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = p[SZ_HEADER + SZ_GASMIX * flags + 5] / 100.0;
|
||||
gasmix->oxygen = p[SZ_HEADER + SZ_GASMIX * flags + 4] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -213,6 +191,7 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
tank->gasmix = flags;
|
||||
tank->beginpressure = array_uint16_le(p + 6) * PSI / BAR;
|
||||
tank->endpressure = array_uint16_le(p + 14) * PSI / BAR;
|
||||
tank->usage = DC_TANK_USAGE_NONE;
|
||||
break;
|
||||
case DC_FIELD_DIVEMODE:
|
||||
switch(p[0x24]) {
|
||||
@ -310,19 +289,19 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
|
||||
// Time (seconds).
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/1000 bar).
|
||||
unsigned int depth = array_uint16_le (data + offset + 0);
|
||||
sample.depth = (signed int)(depth - atmospheric) * (BAR / 1000.0) / parser->hydrostatic;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Pressure (1 psi).
|
||||
unsigned int pressure = array_uint16_le (data + offset + 2);
|
||||
sample.pressure.tank = tank;
|
||||
sample.pressure.value = pressure * PSI / BAR;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
|
||||
// Current gas mix
|
||||
unsigned int gasmix = data[offset + 4];
|
||||
@ -338,14 +317,14 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
// Temperature (1 °F).
|
||||
unsigned int temperature = data[offset + 8];
|
||||
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
// violation status
|
||||
sample.event.type = 0;
|
||||
@ -355,15 +334,15 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
unsigned int violation = data[offset + 11];
|
||||
if (violation & 0x01) {
|
||||
sample.event.type = SAMPLE_EVENT_ASCENT;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
if (violation & 0x04) {
|
||||
sample.event.type = SAMPLE_EVENT_CEILING;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
if (violation & 0x08) {
|
||||
sample.event.type = SAMPLE_EVENT_PO2;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
// NDL & deco
|
||||
@ -378,7 +357,8 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.time = ndl;
|
||||
sample.deco.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
|
||||
offset += SZ_SEGMENT;
|
||||
}
|
||||
|
||||
@ -51,7 +51,6 @@
|
||||
#include "context-private.h"
|
||||
#include "iostream-private.h"
|
||||
#include "iterator-private.h"
|
||||
#include "descriptor-private.h"
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -455,7 +454,7 @@ dc_bluetooth_iterator_next (dc_iterator_t *abstract, void *out)
|
||||
INFO (abstract->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s",
|
||||
address, name ? name : "");
|
||||
|
||||
if (!dc_descriptor_filter (iterator->descriptor, DC_TRANSPORT_BLUETOOTH, name, NULL)) {
|
||||
if (!dc_descriptor_filter (iterator->descriptor, DC_TRANSPORT_BLUETOOTH, name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
180
src/checksum.c
180
src/checksum.c
@ -68,8 +68,13 @@ checksum_xor_uint8 (const unsigned char data[], unsigned int size, unsigned char
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Polynomial: 0x1021
|
||||
* RefIn: False
|
||||
* RefOut: False
|
||||
*/
|
||||
unsigned short
|
||||
checksum_crc16_ccitt (const unsigned char data[], unsigned int size, unsigned short init)
|
||||
checksum_crc16_ccitt (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout)
|
||||
{
|
||||
static const unsigned short crc_ccitt_table[] = {
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
|
||||
@ -110,11 +115,170 @@ checksum_crc16_ccitt (const unsigned char data[], unsigned int size, unsigned sh
|
||||
for (unsigned int i = 0; i < size; ++i)
|
||||
crc = (crc << 8) ^ crc_ccitt_table[(crc >> 8) ^ data[i]];
|
||||
|
||||
return crc;
|
||||
return crc ^ xorout;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Polynomial: 0x1021
|
||||
* RefIn: True
|
||||
* RefOut: True
|
||||
*/
|
||||
unsigned short
|
||||
checksum_crc16r_ccitt (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout)
|
||||
{
|
||||
static const unsigned short crc_ccitt_table[] = {
|
||||
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
|
||||
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
|
||||
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
|
||||
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
|
||||
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
|
||||
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
|
||||
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
|
||||
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
|
||||
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
|
||||
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
|
||||
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
|
||||
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
|
||||
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
|
||||
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
|
||||
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
|
||||
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
|
||||
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
|
||||
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
|
||||
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
|
||||
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
|
||||
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
|
||||
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
|
||||
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
|
||||
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
|
||||
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
|
||||
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
|
||||
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
|
||||
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
|
||||
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
|
||||
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
|
||||
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
|
||||
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
|
||||
};
|
||||
|
||||
unsigned short crc = init;
|
||||
for (unsigned int i = 0; i < size; ++i)
|
||||
crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ data[i]) & 0xff];
|
||||
|
||||
return crc ^ xorout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Polynomial: 0x8005
|
||||
* RefIn: False
|
||||
* RefOut: False
|
||||
*/
|
||||
unsigned short
|
||||
checksum_crc16_ansi (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout)
|
||||
{
|
||||
static const unsigned short crc_ccitt_table[] = {
|
||||
0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
|
||||
0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
|
||||
0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
|
||||
0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
|
||||
0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
|
||||
0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
|
||||
0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
|
||||
0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
|
||||
0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
|
||||
0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
|
||||
0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
|
||||
0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
|
||||
0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
|
||||
0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
|
||||
0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
|
||||
0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
|
||||
0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
|
||||
0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
|
||||
0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
|
||||
0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
|
||||
0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
|
||||
0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
|
||||
0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
|
||||
0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
|
||||
0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
|
||||
0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
|
||||
0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
|
||||
0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
|
||||
0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
|
||||
0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
|
||||
0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
|
||||
0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
|
||||
};
|
||||
|
||||
unsigned short crc = init;
|
||||
for (unsigned int i = 0; i < size; ++i)
|
||||
crc = (crc << 8) ^ crc_ccitt_table[(crc >> 8) ^ data[i]];
|
||||
|
||||
return crc ^ xorout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Polynomial: 0x8005
|
||||
* RefIn: True
|
||||
* RefOut: True
|
||||
*/
|
||||
unsigned short
|
||||
checksum_crc16r_ansi (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout)
|
||||
{
|
||||
static const unsigned short crc_ccitt_table[] = {
|
||||
0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
|
||||
0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
|
||||
0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
|
||||
0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
|
||||
0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
|
||||
0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
|
||||
0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
|
||||
0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
|
||||
0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
|
||||
0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
|
||||
0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
|
||||
0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
|
||||
0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
|
||||
0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
|
||||
0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
|
||||
0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
|
||||
0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
|
||||
0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
|
||||
0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
|
||||
0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
|
||||
0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
|
||||
0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
|
||||
0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
|
||||
0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
|
||||
0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
|
||||
0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
|
||||
0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
|
||||
0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
|
||||
0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
|
||||
0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
|
||||
0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
|
||||
0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
|
||||
};
|
||||
|
||||
unsigned short crc = init;
|
||||
for (unsigned int i = 0; i < size; ++i)
|
||||
crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ data[i]) & 0xff];
|
||||
|
||||
return crc ^ xorout;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Polynomial: 0x04C11DB7
|
||||
* Init: 0xffffffff
|
||||
* XorOut: 0xffffffff
|
||||
* RefIn: True
|
||||
* RefOut: True
|
||||
*/
|
||||
unsigned int
|
||||
checksum_crc32 (const unsigned char data[], unsigned int size)
|
||||
checksum_crc32r (const unsigned char data[], unsigned int size)
|
||||
{
|
||||
static const unsigned int crc_table[] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
@ -158,8 +322,16 @@ checksum_crc32 (const unsigned char data[], unsigned int size)
|
||||
return crc ^ 0xffffffff;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Polynomial: 0x04C11DB7
|
||||
* Init: 0xffffffff
|
||||
* XorOut: 0xffffffff
|
||||
* RefIn: False
|
||||
* RefOut: False
|
||||
*/
|
||||
unsigned int
|
||||
checksum_crc32b (const unsigned char data[], unsigned int size)
|
||||
checksum_crc32 (const unsigned char data[], unsigned int size)
|
||||
{
|
||||
static const unsigned int crc_table[] = {
|
||||
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
|
||||
|
||||
@ -39,14 +39,23 @@ unsigned char
|
||||
checksum_xor_uint8 (const unsigned char data[], unsigned int size, unsigned char init);
|
||||
|
||||
unsigned short
|
||||
checksum_crc16_ccitt (const unsigned char data[], unsigned int size, unsigned short init);
|
||||
checksum_crc16_ccitt (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout);
|
||||
|
||||
unsigned short
|
||||
checksum_crc16r_ccitt (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout);
|
||||
|
||||
unsigned short
|
||||
checksum_crc16_ansi (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout);
|
||||
|
||||
unsigned short
|
||||
checksum_crc16r_ansi (const unsigned char data[], unsigned int size, unsigned short init, unsigned short xorout);
|
||||
|
||||
unsigned int
|
||||
checksum_crc32r (const unsigned char data[], unsigned int size);
|
||||
|
||||
unsigned int
|
||||
checksum_crc32 (const unsigned char data[], unsigned int size);
|
||||
|
||||
unsigned int
|
||||
checksum_crc32b (const unsigned char data[], unsigned int size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -31,6 +31,8 @@
|
||||
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &citizen_aqualand_device_vtable)
|
||||
|
||||
#define SZ_HEADER 32
|
||||
|
||||
typedef struct citizen_aqualand_device_t {
|
||||
dc_device_t base;
|
||||
dc_iostream_t *iostream;
|
||||
@ -200,6 +202,12 @@ citizen_aqualand_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
unsigned char *data = dc_buffer_get_data (buffer);
|
||||
unsigned int size = dc_buffer_get_size (buffer);
|
||||
|
||||
if (size < SZ_HEADER) {
|
||||
ERROR (abstract->context, "Dive header is too small (%u).", size);
|
||||
dc_buffer_free (buffer);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
if (callback && memcmp (data + 0x05, device->fingerprint, sizeof (device->fingerprint)) != 0) {
|
||||
callback (data, size, data + 0x05, sizeof (device->fingerprint), userdata);
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
citizen_aqualand_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
citizen_aqualand_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
citizen_aqualand_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -36,7 +36,6 @@ typedef struct citizen_aqualand_parser_t {
|
||||
dc_parser_t base;
|
||||
} citizen_aqualand_parser_t;
|
||||
|
||||
static dc_status_t citizen_aqualand_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t citizen_aqualand_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -44,7 +43,6 @@ static dc_status_t citizen_aqualand_parser_samples_foreach (dc_parser_t *abstrac
|
||||
static const dc_parser_vtable_t citizen_aqualand_parser_vtable = {
|
||||
sizeof(citizen_aqualand_parser_t),
|
||||
DC_FAMILY_CITIZEN_AQUALAND,
|
||||
citizen_aqualand_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -56,7 +54,7 @@ static const dc_parser_vtable_t citizen_aqualand_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
citizen_aqualand_parser_t *parser = NULL;
|
||||
|
||||
@ -64,7 +62,7 @@ citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (citizen_aqualand_parser_t *) dc_parser_allocate (context, &citizen_aqualand_parser_vtable);
|
||||
parser = (citizen_aqualand_parser_t *) dc_parser_allocate (context, &citizen_aqualand_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -76,13 +74,6 @@ citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
citizen_aqualand_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -241,15 +232,15 @@ citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
|
||||
// Time
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth
|
||||
if (metric)
|
||||
sample.depth = depth / 10.0;
|
||||
else
|
||||
sample.depth = depth * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Temperature
|
||||
if (time % 300 == 0) {
|
||||
@ -260,7 +251,7 @@ citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
sample.temperature = temperature / 10.0;
|
||||
else
|
||||
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
cochran_commander_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
cochran_commander_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
cochran_commander_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -99,7 +99,6 @@ typedef struct cochran_commander_parser_t {
|
||||
unsigned int nevents;
|
||||
} cochran_commander_parser_t ;
|
||||
|
||||
static dc_status_t cochran_commander_parser_set_data (dc_parser_t *parser, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t cochran_commander_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime);
|
||||
static dc_status_t cochran_commander_parser_get_field (dc_parser_t *parser, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t cochran_commander_parser_samples_foreach (dc_parser_t *parser, dc_sample_callback_t callback, void *userdata);
|
||||
@ -107,7 +106,6 @@ static dc_status_t cochran_commander_parser_samples_foreach (dc_parser_t *parser
|
||||
static const dc_parser_vtable_t cochran_commander_parser_vtable = {
|
||||
sizeof(cochran_commander_parser_t),
|
||||
DC_FAMILY_COCHRAN_COMMANDER,
|
||||
cochran_commander_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -315,7 +313,7 @@ cochran_commander_handle_event (cochran_commander_parser_t *parser, unsigned cha
|
||||
sample.event.time = 0;
|
||||
sample.event.value = 0;
|
||||
sample.event.flags = event->flag;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,7 +350,7 @@ cochran_commander_backparse(cochran_commander_parser_t *parser, const unsigned c
|
||||
|
||||
|
||||
dc_status_t
|
||||
cochran_commander_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
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_t *parser = NULL;
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
@ -361,7 +359,7 @@ cochran_commander_parser_create (dc_parser_t **out, dc_context_t *context, unsig
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (cochran_commander_parser_t *) dc_parser_allocate (context, &cochran_commander_parser_vtable);
|
||||
parser = (cochran_commander_parser_t *) dc_parser_allocate (context, &cochran_commander_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -407,13 +405,6 @@ error_free:
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cochran_commander_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cochran_commander_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -514,6 +505,7 @@ cochran_commander_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
// Gas percentages are decimal and encoded as
|
||||
// highbyte = integer portion
|
||||
// lowbyte = decimal portion, divide by 256 to get decimal value
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->oxygen = array_uint16_le (data + layout->oxygen + 2 * flags) / 256.0 / 100;
|
||||
if (layout->helium == UNSUPPORTED) {
|
||||
gasmix->helium = 0;
|
||||
@ -578,26 +570,26 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
||||
unsigned int temp = samples[0]; // Half degrees F
|
||||
unsigned int depth = samples[1]; // Half feet
|
||||
|
||||
last_sample_time = sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
last_sample_time = sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
sample.depth = (depth / 2.0) * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
sample.temperature = (temp / 2.0 - 32.0) / 1.8;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
sample.gasmix = 0;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
|
||||
while (offset < size) {
|
||||
const unsigned char *s = samples + offset;
|
||||
|
||||
sample.time = time;
|
||||
sample.time = time * 1000;
|
||||
if (last_sample_time != sample.time) {
|
||||
// We haven't issued this time yet.
|
||||
last_sample_time = sample.time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
}
|
||||
|
||||
if (*s & 0x80) {
|
||||
@ -615,7 +607,8 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.time = 60; // We don't know the duration
|
||||
sample.deco.depth = deco_ceiling * FEET;
|
||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||
break;
|
||||
case 0xAD: // Increment ceiling (shallower)
|
||||
deco_ceiling -= 10; // feet
|
||||
@ -623,7 +616,8 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = deco_ceiling * FEET;
|
||||
sample.deco.time = 60; // We don't know the duration
|
||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||
break;
|
||||
default:
|
||||
cochran_commander_handle_event(parser, s[0], callback, userdata);
|
||||
@ -636,7 +630,7 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
||||
else
|
||||
temp += (*s & 0x0f);
|
||||
sample.temperature = (temp / 2.0 - 32.0) / 1.8;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
|
||||
offset++;
|
||||
@ -650,7 +644,7 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
||||
depth += s[0] & 0x3f;
|
||||
|
||||
sample.depth = (depth / 2.0) * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
offset++;
|
||||
time += sample_interval;
|
||||
@ -714,27 +708,27 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
start_depth = array_uint16_le (data + layout->start_depth) / 256.0;
|
||||
}
|
||||
|
||||
last_sample_time = sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
last_sample_time = sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
sample.depth = start_depth * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
sample.temperature = (data[layout->start_temp] - 32.0) / 1.8;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
sample.gasmix = 0;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
unsigned int last_gasmix = sample.gasmix;
|
||||
|
||||
while (offset < size) {
|
||||
const unsigned char *s = samples + offset;
|
||||
|
||||
sample.time = time;
|
||||
sample.time = time * 1000;
|
||||
if (last_sample_time != sample.time) {
|
||||
// We haven't issued this time yet.
|
||||
last_sample_time = sample.time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
}
|
||||
|
||||
// If corrupt_dive end before offset
|
||||
@ -774,7 +768,8 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.time = (array_uint16_le(s + 3) + 1) * 60;
|
||||
sample.deco.depth = deco_ceiling * FEET;
|
||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||
break;
|
||||
case 0xAD: // Increment ceiling (shallower)
|
||||
deco_ceiling -= 10; // feet
|
||||
@ -782,7 +777,8 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = deco_ceiling * FEET;
|
||||
sample.deco.time = (array_uint16_le(s + 3) + 1) * 60;
|
||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||
break;
|
||||
case 0xC0: // Switched to FO2 21% mode (surface)
|
||||
// Event seen upon surfacing
|
||||
@ -791,14 +787,14 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
case 0xEF: // Switched to gas blend 2
|
||||
if (last_gasmix != 1) {
|
||||
sample.gasmix = 1;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
last_gasmix = sample.gasmix;
|
||||
}
|
||||
break;
|
||||
case 0xF3: // Switched to gas blend 1
|
||||
if (last_gasmix != 0) {
|
||||
sample.gasmix = 0;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
last_gasmix = sample.gasmix;
|
||||
}
|
||||
break;
|
||||
@ -818,7 +814,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
depth += (s[0] & 0x3f);
|
||||
|
||||
sample.depth = (start_depth + depth / 4.0) * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Ascent rate is logged in the 0th sample, temp in the 1st, repeat.
|
||||
if (time % 2 == 0) {
|
||||
@ -834,7 +830,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
double temperature = s[1] / 2.0 + 20.0;
|
||||
sample.temperature = (temperature - 32.0) / 1.8;
|
||||
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
|
||||
// Cochran EMC models store NDL and deco stop time
|
||||
@ -855,7 +851,8 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.time = deco_time * 60;
|
||||
sample.deco.depth = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
}
|
||||
break;
|
||||
case 23:
|
||||
@ -865,7 +862,8 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = deco_ceiling * FEET;
|
||||
sample.deco.time = deco_time * 60;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -38,6 +38,8 @@
|
||||
#define SZ_PACKET 0x80
|
||||
#define SZ_PAGE (SZ_PACKET / 4)
|
||||
|
||||
#define SZ_HEADER 32
|
||||
|
||||
#define IQ700 0x05
|
||||
#define EDY 0x08
|
||||
|
||||
@ -522,6 +524,13 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (length < SZ_HEADER) {
|
||||
ERROR (abstract->context, "Dive header is too small (%u).", length);
|
||||
dc_rbstream_free (rbstream);
|
||||
free (buffer);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned char *p = buffer + offset;
|
||||
|
||||
if (memcmp (p, device->fingerprint, sizeof (device->fingerprint)) == 0)
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
cressi_edy_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
cressi_edy_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
cressi_edy_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -31,6 +31,8 @@
|
||||
#define IQ700 0x05
|
||||
#define EDY 0x08
|
||||
|
||||
#define SZ_HEADER 32
|
||||
|
||||
typedef struct cressi_edy_parser_t cressi_edy_parser_t;
|
||||
|
||||
struct cressi_edy_parser_t {
|
||||
@ -38,7 +40,6 @@ struct cressi_edy_parser_t {
|
||||
unsigned int model;
|
||||
};
|
||||
|
||||
static dc_status_t cressi_edy_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -46,7 +47,6 @@ static dc_status_t cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_
|
||||
static const dc_parser_vtable_t cressi_edy_parser_vtable = {
|
||||
sizeof(cressi_edy_parser_t),
|
||||
DC_FAMILY_CRESSI_EDY,
|
||||
cressi_edy_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -73,7 +73,7 @@ cressi_edy_parser_count_gasmixes (const unsigned char *data)
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
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_t *parser = NULL;
|
||||
|
||||
@ -81,7 +81,7 @@ cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (cressi_edy_parser_t *) dc_parser_allocate (context, &cressi_edy_parser_vtable);
|
||||
parser = (cressi_edy_parser_t *) dc_parser_allocate (context, &cressi_edy_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -96,17 +96,10 @@ cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cressi_edy_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
if (abstract->size < 32)
|
||||
if (abstract->size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
const unsigned char *p = abstract->data;
|
||||
@ -130,7 +123,7 @@ cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
||||
{
|
||||
cressi_edy_parser_t *parser = (cressi_edy_parser_t *) abstract;
|
||||
|
||||
if (abstract->size < 32)
|
||||
if (abstract->size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
const unsigned char *p = abstract->data;
|
||||
@ -152,6 +145,7 @@ cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
||||
*((unsigned int *) value) = cressi_edy_parser_count_gasmixes(p);
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->oxygen = bcd2dec (p[0x17 - flags]) / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -188,7 +182,7 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
unsigned int ngasmixes = cressi_edy_parser_count_gasmixes(data);
|
||||
unsigned int gasmix = 0xFFFFFFFF;
|
||||
|
||||
unsigned int offset = 32;
|
||||
unsigned int offset = SZ_HEADER;
|
||||
while (offset + 2 <= size) {
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
@ -201,13 +195,13 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
|
||||
// Time (seconds).
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
unsigned int depth = bcd2dec (data[offset + 0] & 0x0F) * 100 + bcd2dec (data[offset + 1]);
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Current gasmix
|
||||
if (ngasmixes) {
|
||||
@ -220,7 +214,7 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
}
|
||||
if (idx != gasmix) {
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix = idx;
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ cressi_goa_device_send (cressi_goa_device_t *device, unsigned char cmd, const un
|
||||
if (size) {
|
||||
memcpy (packet + 5, data, size);
|
||||
}
|
||||
crc = checksum_crc16_ccitt (packet + 3, size + 2, 0x000);
|
||||
crc = checksum_crc16_ccitt (packet + 3, size + 2, 0x000, 0x0000);
|
||||
packet[5 + size + 0] = (crc ) & 0xFF; // Low
|
||||
packet[5 + size + 1] = (crc >> 8) & 0xFF; // High
|
||||
packet[5 + size + 2] = TRAILER;
|
||||
@ -155,7 +155,7 @@ cressi_goa_device_receive (cressi_goa_device_t *device, unsigned char data[], un
|
||||
|
||||
// Verify the checksum of the packet.
|
||||
unsigned short crc = array_uint16_le (packet + length + 5);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (packet + 3, length + 2, 0x0000);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (packet + 3, length + 2, 0x0000, 0x0000);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected answer checksum.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
@ -203,7 +203,7 @@ cressi_goa_device_download (cressi_goa_device_t *device, dc_buffer_t *buffer, dc
|
||||
|
||||
// Verify the checksum of the packet.
|
||||
unsigned short crc = array_uint16_le (packet + sizeof(packet) - 2);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (packet + 3, sizeof(packet) - 5, 0x0000);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (packet + 3, sizeof(packet) - 5, 0x0000, 0x0000);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected answer checksum.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
cressi_goa_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
cressi_goa_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
cressi_goa_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -62,7 +62,6 @@ typedef struct cressi_goa_layout_t {
|
||||
unsigned int temperature;
|
||||
} cressi_goa_layout_t;
|
||||
|
||||
static dc_status_t cressi_goa_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -70,7 +69,6 @@ static dc_status_t cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_
|
||||
static const dc_parser_vtable_t cressi_goa_parser_vtable = {
|
||||
sizeof(cressi_goa_parser_t),
|
||||
DC_FAMILY_CRESSI_GOA,
|
||||
cressi_goa_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -128,7 +126,7 @@ static const cressi_goa_layout_t layouts[] = {
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
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_t *parser = NULL;
|
||||
|
||||
@ -136,7 +134,7 @@ cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (cressi_goa_parser_t *) dc_parser_allocate (context, &cressi_goa_parser_vtable);
|
||||
parser = (cressi_goa_parser_t *) dc_parser_allocate (context, &cressi_goa_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -149,12 +147,6 @@ cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
cressi_goa_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -250,6 +242,7 @@ cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
||||
*((unsigned int *) value) = ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->oxygen = data[layout->gasmix + 2 * flags + 1] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -329,25 +322,25 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
|
||||
if (complete) {
|
||||
// Time (seconds).
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Temperature (1/10 °C).
|
||||
if (have_temperature) {
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
have_temperature = 0;
|
||||
}
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Gas change
|
||||
if (divemode == SCUBA || divemode == NITROX) {
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ cressi_leonardo_make_ascii (const unsigned char raw[], unsigned int rsize, unsig
|
||||
array_convert_bin2hex (raw, rsize, ascii + 1, 2 * rsize);
|
||||
|
||||
// Checksum
|
||||
unsigned short crc = checksum_crc16_ccitt (ascii + 1, 2 * rsize, 0xffff);
|
||||
unsigned short crc = checksum_crc16_ccitt (ascii + 1, 2 * rsize, 0xffff, 0x0000);
|
||||
unsigned char checksum[] = {
|
||||
(crc >> 8) & 0xFF, // High
|
||||
(crc ) & 0xFF}; // Low
|
||||
@ -129,7 +129,7 @@ cressi_leonardo_packet (cressi_leonardo_device_t *device, const unsigned char co
|
||||
|
||||
// Verify the checksum of the packet.
|
||||
unsigned short crc = array_uint16_be (checksum);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (answer + 1, asize - 6, 0xffff);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (answer + 1, asize - 6, 0xffff, 0x0000);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected answer checksum.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
@ -372,7 +372,7 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
||||
|
||||
// Verify the checksum.
|
||||
unsigned int csum1 = array_uint16_be (checksum);
|
||||
unsigned int csum2 = checksum_crc16_ccitt (data, SZ_MEMORY, 0xffff);
|
||||
unsigned int csum2 = checksum_crc16_ccitt (data, SZ_MEMORY, 0xffff, 0x0000);
|
||||
if (csum1 != csum2) {
|
||||
ERROR (abstract->context, "Unexpected answer bytes.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
cressi_leonardo_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
cressi_leonardo_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
cressi_leonardo_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -39,7 +39,6 @@ struct cressi_leonardo_parser_t {
|
||||
unsigned int model;
|
||||
};
|
||||
|
||||
static dc_status_t cressi_leonardo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t cressi_leonardo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -47,7 +46,6 @@ static dc_status_t cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract
|
||||
static const dc_parser_vtable_t cressi_leonardo_parser_vtable = {
|
||||
sizeof(cressi_leonardo_parser_t),
|
||||
DC_FAMILY_CRESSI_LEONARDO,
|
||||
cressi_leonardo_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -59,7 +57,7 @@ static const dc_parser_vtable_t cressi_leonardo_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
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_t *parser = NULL;
|
||||
|
||||
@ -67,7 +65,7 @@ cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, unsigne
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (cressi_leonardo_parser_t *) dc_parser_allocate (context, &cressi_leonardo_parser_vtable);
|
||||
parser = (cressi_leonardo_parser_t *) dc_parser_allocate (context, &cressi_leonardo_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -81,13 +79,6 @@ cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, unsigne
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cressi_leonardo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -146,6 +137,7 @@ cressi_leonardo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, u
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->oxygen = data[0x19] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -196,12 +188,12 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
|
||||
// Time (seconds).
|
||||
time += surftime;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
offset += 4;
|
||||
} else {
|
||||
@ -211,17 +203,17 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
|
||||
// Time (seconds).
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Gas change.
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
@ -229,9 +221,13 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
if (ascent) {
|
||||
sample.event.type = SAMPLE_EVENT_ASCENT;
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
if (ascent < 3)
|
||||
// Turn the overly sensitive ascent warnings of this dive computer into info events
|
||||
sample.event.flags = SAMPLE_FLAGS_SEVERITY_INFO;
|
||||
else
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = ascent;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
offset += 2;
|
||||
|
||||
@ -36,7 +36,7 @@ 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);
|
||||
deepblu_cosmiq_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -41,7 +41,6 @@ typedef struct deepblu_cosmiq_parser_t {
|
||||
double hydrostatic;
|
||||
} deepblu_cosmiq_parser_t;
|
||||
|
||||
static dc_status_t deepblu_cosmiq_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
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);
|
||||
@ -50,7 +49,6 @@ static dc_status_t deepblu_cosmiq_parser_samples_foreach (dc_parser_t *abstract,
|
||||
static const dc_parser_vtable_t deepblu_cosmiq_parser_vtable = {
|
||||
sizeof(deepblu_cosmiq_parser_t),
|
||||
DC_FAMILY_DEEPBLU_COSMIQ,
|
||||
deepblu_cosmiq_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
deepblu_cosmiq_parser_set_density, /* set_density */
|
||||
@ -61,7 +59,7 @@ static const dc_parser_vtable_t deepblu_cosmiq_parser_vtable = {
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
deepblu_cosmiq_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
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;
|
||||
|
||||
@ -69,7 +67,7 @@ deepblu_cosmiq_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (deepblu_cosmiq_parser_t *) dc_parser_allocate (context, &deepblu_cosmiq_parser_vtable);
|
||||
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;
|
||||
@ -83,12 +81,6 @@ deepblu_cosmiq_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_parser_set_density (dc_parser_t *abstract, double density)
|
||||
{
|
||||
@ -151,6 +143,7 @@ deepblu_cosmiq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
*((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;
|
||||
@ -204,14 +197,14 @@ deepblu_cosmiq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
offset += SZ_SAMPLE;
|
||||
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
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);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
@ -35,7 +35,7 @@ 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);
|
||||
deepsix_excursion_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -112,7 +112,6 @@ typedef struct deepsix_excursion_parser_t {
|
||||
deepsix_excursion_gasmix_t gasmix[MAX_GASMIXES];
|
||||
} deepsix_excursion_parser_t;
|
||||
|
||||
static dc_status_t deepsix_excursion_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
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);
|
||||
@ -122,7 +121,6 @@ static dc_status_t deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abs
|
||||
static const dc_parser_vtable_t deepsix_parser_vtable = {
|
||||
sizeof(deepsix_excursion_parser_t),
|
||||
DC_FAMILY_DEEPSIX_EXCURSION,
|
||||
deepsix_excursion_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -185,7 +183,7 @@ deepsix_excursion_find_gasmix(deepsix_excursion_parser_t *parser, unsigned int o
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
deepsix_excursion_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
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;
|
||||
|
||||
@ -193,7 +191,7 @@ deepsix_excursion_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (deepsix_excursion_parser_t *) dc_parser_allocate (context, &deepsix_parser_vtable);
|
||||
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;
|
||||
@ -213,23 +211,6 @@ deepsix_excursion_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
deepsix_excursion_parser_t *parser = (deepsix_excursion_parser_t *) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
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;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -322,6 +303,7 @@ deepsix_excursion_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
*((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;
|
||||
@ -423,11 +405,11 @@ deepsix_excursion_parser_samples_foreach_v0 (dc_parser_t *abstract, dc_sample_ca
|
||||
|
||||
if (type == TEMPERATURE) {
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback(DC_SAMPLE_TIME, sample, userdata);
|
||||
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 (callback) callback(DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
}
|
||||
|
||||
if (type == ALARM) {
|
||||
@ -440,11 +422,11 @@ deepsix_excursion_parser_samples_foreach_v0 (dc_parser_t *abstract, dc_sample_ca
|
||||
length = 8;
|
||||
} else if (temperature >= 10) {
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
} else {
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
} else if (type == DECO) {
|
||||
unsigned int deco = array_uint16_le(data + offset + 4);
|
||||
@ -454,7 +436,7 @@ deepsix_excursion_parser_samples_foreach_v0 (dc_parser_t *abstract, dc_sample_ca
|
||||
} 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);
|
||||
if (callback) callback(DC_SAMPLE_CNS, &sample, userdata);
|
||||
}
|
||||
|
||||
offset += length;
|
||||
@ -591,12 +573,12 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca
|
||||
|
||||
// Time (seconds).
|
||||
time += samplerate;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
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);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
offset += 2;
|
||||
|
||||
// event info
|
||||
@ -664,7 +646,7 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca
|
||||
break;
|
||||
}
|
||||
if (sample.event.type != SAMPLE_EVENT_NONE) {
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -686,7 +668,7 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca
|
||||
}
|
||||
|
||||
sample.gasmix = mix_idx;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
break;
|
||||
case EVENT_SAMPLES_MISSED:
|
||||
count = array_uint16_le(data + offset + event_offset);
|
||||
@ -727,12 +709,12 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca
|
||||
case SAMPLE_TEMPERATURE:
|
||||
value = array_uint16_le(data + offset);
|
||||
sample.temperature = value / 10.0;
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
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);
|
||||
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata);
|
||||
break;
|
||||
case SAMPLE_DECO_NDL:
|
||||
deco_flags = data[offset];
|
||||
@ -752,7 +734,7 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca
|
||||
sample.deco.depth = 0;
|
||||
sample.deco.time = deco_ndl_tts;
|
||||
}
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
175
src/descriptor.c
175
src/descriptor.c
@ -23,7 +23,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "descriptor-private.h"
|
||||
#include <libdivecomputer/descriptor.h>
|
||||
#include <libdivecomputer/usbhid.h>
|
||||
#include <libdivecomputer/usb.h>
|
||||
|
||||
#include "iterator-private.h"
|
||||
#include "platform.h"
|
||||
|
||||
@ -36,38 +39,29 @@
|
||||
values, \
|
||||
C_ARRAY_SIZE(values) - isnullterminated, \
|
||||
C_ARRAY_ITEMSIZE(values), \
|
||||
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))
|
||||
match)
|
||||
|
||||
typedef int (*dc_match_t)(const void *, const void *);
|
||||
|
||||
typedef int (*dc_filter_t) (dc_transport_t transport, const void *userdata, void *params);
|
||||
typedef int (*dc_filter_t) (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
|
||||
static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_suunto (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_shearwater (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_hw (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_mares (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_divesystem (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_mclean (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_atomic (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_deepsix (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 int dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_suunto (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_shearwater (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_hw (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_tecdiving (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_mares (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_divesystem (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_mclean (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_atomic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_deepsix (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_deepblu (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_oceans (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_divesoft (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
|
||||
// Not merged upstream yet
|
||||
static int dc_filter_garmin (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_garmin (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
|
||||
static dc_status_t dc_descriptor_iterator_next (dc_iterator_t *iterator, void *item);
|
||||
|
||||
@ -179,7 +173,10 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Scubapro", "G2 TEK", DC_FAMILY_UWATEC_SMART, 0x31, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G2", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G2 Console", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G3", DC_FAMILY_UWATEC_SMART, 0x34, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G2 HUD", DC_FAMILY_UWATEC_SMART, 0x42, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "Luna 2.0 AI", DC_FAMILY_UWATEC_SMART, 0x50, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "Luna 2.0", DC_FAMILY_UWATEC_SMART, 0x51, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
/* Reefnet */
|
||||
{"Reefnet", "Sensus", DC_FAMILY_REEFNET_SENSUS, 1, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Reefnet", "Sensus Pro", DC_FAMILY_REEFNET_SENSUSPRO, 2, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -278,6 +275,9 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Aqualung", "i470TC", DC_FAMILY_OCEANIC_ATOM2, 0x4743, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i200Cv2", DC_FAMILY_OCEANIC_ATOM2, 0x4749, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Oceanic", "Geo Air", DC_FAMILY_OCEANIC_ATOM2, 0x474B, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
/* Pelagic I330R */
|
||||
{"Apeks", "DSX", DC_FAMILY_PELAGIC_I330R, 0x4741, DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i330R", DC_FAMILY_PELAGIC_I330R, 0x4744, DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
/* Mares Nemo */
|
||||
{"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -363,6 +363,7 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Shearwater", "Peregrine", DC_FAMILY_SHEARWATER_PETREL, 9, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Petrel 3", DC_FAMILY_SHEARWATER_PETREL, 10, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Perdix 2", DC_FAMILY_SHEARWATER_PETREL, 11, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Tern", DC_FAMILY_SHEARWATER_PETREL, 12, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
/* Dive Rite NiTek Q */
|
||||
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Citizen Hyper Aqualand */
|
||||
@ -416,6 +417,20 @@ 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 Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x74, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iX3M 2021 Pro Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x75, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iDive 2 Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x80, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Fancy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x81, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x82, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x83, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x84, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Tech", DC_FAMILY_DIVESYSTEM_IDIVE, 0x85, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x86, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Gauge", DC_FAMILY_DIVESYSTEM_IDIVE, 0x90, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x91, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x92, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x93, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Tech", DC_FAMILY_DIVESYSTEM_IDIVE, 0x94, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x95, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "ATOM", DC_FAMILY_DIVESYSTEM_IDIVE, 0x96, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Gauge", DC_FAMILY_DIVESYSTEM_IDIVE, 0x100, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x101, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x102, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
@ -445,7 +460,6 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"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},
|
||||
{"Tusa", "TC1", 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},
|
||||
@ -454,13 +468,18 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Deepblu", "Cosmiq+", DC_FAMILY_DEEPBLU_COSMIQ, 0, DC_TRANSPORT_BLE, dc_filter_deepblu},
|
||||
/* Oceans S1 */
|
||||
{"Oceans", "S1", DC_FAMILY_OCEANS_S1, 0, DC_TRANSPORT_BLE, dc_filter_oceans},
|
||||
/* Divesoft Freedom */
|
||||
{"Divesoft", "Freedom", DC_FAMILY_DIVESOFT_FREEDOM, 19, DC_TRANSPORT_BLE, dc_filter_divesoft},
|
||||
{"Divesoft", "Liberty", DC_FAMILY_DIVESOFT_FREEDOM, 10, DC_TRANSPORT_BLE, dc_filter_divesoft},
|
||||
|
||||
// Not merged upstream yet
|
||||
/* Garmin -- model numbers as defined in FIT format; USB product id is (0x4000 | model) */
|
||||
/* for the Mk1 we are using the model of the global model - the APAC model is 2991 */
|
||||
/* for the Mk2 we are using the model of the global model - the APAC model is 3702 */
|
||||
{"Garmin", "Descent Mk1", DC_FAMILY_GARMIN, 2859, DC_TRANSPORT_USBSTORAGE, dc_filter_garmin},
|
||||
{"Garmin", "Descent Mk2/Mk2i", DC_FAMILY_GARMIN, 3258, DC_TRANSPORT_USBSTORAGE, dc_filter_garmin},
|
||||
/* for the Mk1 we are using the model of the global model */
|
||||
/* for the Mk2/Mk3 we are using the model of the Mk2 global model */
|
||||
/* see garmin_parser.c for a more comprehensive list of models */
|
||||
{"Garmin", "Descent Mk1", DC_FAMILY_GARMIN, 2859, DC_TRANSPORT_USBSTORAGE, NULL},
|
||||
{"Garmin", "Descent Mk2(i)/Mk3(i)", DC_FAMILY_GARMIN, 3258, DC_TRANSPORT_USBSTORAGE, NULL},
|
||||
{"FIT", "File import", DC_FAMILY_GARMIN, 0, DC_TRANSPORT_USBSTORAGE, NULL },
|
||||
};
|
||||
|
||||
static int
|
||||
@ -499,6 +518,15 @@ dc_match_usb (const void *key, const void *value)
|
||||
return k->vid == v->vid && k->pid == v->pid;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_match_usbhid (const void *key, const void *value)
|
||||
{
|
||||
const dc_usbhid_desc_t *k = (const dc_usbhid_desc_t *) key;
|
||||
const dc_usbhid_desc_t *v = (const dc_usbhid_desc_t *) value;
|
||||
|
||||
return k->vid == v->vid && k->pid == v->pid;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_match_number_with_prefix (const void *key, const void *value)
|
||||
{
|
||||
@ -539,16 +567,13 @@ dc_match_oceanic (const void *key, const void *value)
|
||||
}
|
||||
|
||||
static int
|
||||
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)
|
||||
dc_filter_internal (const void *key, const void *values, size_t count, size_t size, dc_match_t match)
|
||||
{
|
||||
if (key == NULL)
|
||||
return 1;
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
if (match (key, (const unsigned char *) values + i * size)) {
|
||||
if (params_src && params_dst) {
|
||||
memcpy (params_dst, params_src, params_size);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -563,7 +588,8 @@ static const char * const rfcomm[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static int dc_filter_uwatec (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 const char * const irda[] = {
|
||||
"Aladin Smart Com",
|
||||
@ -574,7 +600,7 @@ static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, voi
|
||||
"UWATEC Galileo",
|
||||
"UWATEC Galileo Sol",
|
||||
};
|
||||
static const dc_usb_desc_t usbhid[] = {
|
||||
static const dc_usbhid_desc_t usbhid[] = {
|
||||
{0x2e6c, 0x3201}, // G2, G2 TEK
|
||||
{0x2e6c, 0x3211}, // G2 Console
|
||||
{0x2e6c, 0x4201}, // G2 HUD
|
||||
@ -587,12 +613,15 @@ static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, voi
|
||||
"A1",
|
||||
"A2",
|
||||
"G2 TEK",
|
||||
"Galileo 3",
|
||||
"Luna 2.0 AI",
|
||||
"Luna 2.0",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_IRDA) {
|
||||
return DC_FILTER_INTERNAL (userdata, irda, 0, dc_match_name);
|
||||
} else if (transport == DC_TRANSPORT_USBHID) {
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usb);
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usbhid);
|
||||
} else if (transport == DC_TRANSPORT_BLE) {
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name);
|
||||
}
|
||||
@ -600,9 +629,10 @@ static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, voi
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_suunto (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 const dc_usb_desc_t usbhid[] = {
|
||||
static const dc_usbhid_desc_t usbhid[] = {
|
||||
{0x1493, 0x0030}, // Eon Steel
|
||||
{0x1493, 0x0033}, // Eon Core
|
||||
{0x1493, 0x0035}, // D5
|
||||
@ -616,7 +646,7 @@ static int dc_filter_suunto (dc_transport_t transport, const void *userdata, voi
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_USBHID) {
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usb);
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usbhid);
|
||||
} else if (transport == DC_TRANSPORT_BLE) {
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix);
|
||||
}
|
||||
@ -624,7 +654,8 @@ static int dc_filter_suunto (dc_transport_t transport, const void *userdata, voi
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_hw (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 const char * const bluetooth[] = {
|
||||
"OSTC",
|
||||
@ -640,7 +671,8 @@ static int dc_filter_hw (dc_transport_t transport, const void *userdata, void *p
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_shearwater (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 const char * const bluetooth[] = {
|
||||
"Predator",
|
||||
@ -652,6 +684,7 @@ static int dc_filter_shearwater (dc_transport_t transport, const void *userdata,
|
||||
"Perdix 2",
|
||||
"Teric",
|
||||
"Peregrine",
|
||||
"Tern"
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
|
||||
@ -663,7 +696,8 @@ static int dc_filter_shearwater (dc_transport_t transport, const void *userdata,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_tecdiving (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 const char * const bluetooth[] = {
|
||||
"DiveComputer",
|
||||
@ -678,7 +712,8 @@ static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_mares (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 const char * const bluetooth[] = {
|
||||
"Mares bluelink pro",
|
||||
@ -692,11 +727,13 @@ static int dc_filter_mares (dc_transport_t transport, const void *userdata, void
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_divesystem (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 const char * const bluetooth[] = {
|
||||
"DS",
|
||||
"IX5M",
|
||||
"RATIO-",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
|
||||
@ -706,7 +743,8 @@ static int dc_filter_divesystem (dc_transport_t transport, const void *userdata,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_oceanic (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 const unsigned int model[] = {
|
||||
0x4552, // Oceanic Pro Plus X
|
||||
@ -720,8 +758,10 @@ static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, vo
|
||||
0x4654, // Oceanic Veo 4.0
|
||||
0x4655, // Sherwood Wisdom 4
|
||||
0x4656, // Oceanic Pro Plus 4
|
||||
0x4741, // Apeks DSX
|
||||
0x4742, // Sherwood Beacon
|
||||
0x4743, // Aqualung i470TC
|
||||
0x4744, // Aqualung i330R
|
||||
0x4749, // Aqualung i200C (newer model)
|
||||
0x474B, // Oceanic Geo Air
|
||||
};
|
||||
@ -733,7 +773,8 @@ static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, vo
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_mclean(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 const char * const bluetooth[] = {
|
||||
"McLean Extreme",
|
||||
@ -748,30 +789,27 @@ static int dc_filter_mclean(dc_transport_t transport, const void *userdata, void
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_atomic (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 const dc_usb_desc_t usb[] = {
|
||||
{0x0471, 0x0888}, // Atomic Aquatics Cobalt
|
||||
};
|
||||
|
||||
static const dc_usb_params_t usb_params = {
|
||||
0, 0x82, 0x02
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_USB) {
|
||||
return DC_FILTER_INTERNAL_WITH_PARAMS (userdata, usb, 0, dc_match_usb, params, &usb_params);
|
||||
return DC_FILTER_INTERNAL (userdata, usb, 0, dc_match_usb);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_deepsix (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 const char * const bluetooth[] = {
|
||||
"EXCURSION",
|
||||
"Crest-CR4",
|
||||
"CENTAURI",
|
||||
"TC1",
|
||||
"ALPHA",
|
||||
};
|
||||
|
||||
@ -782,7 +820,8 @@ static int dc_filter_deepsix (dc_transport_t transport, const void *userdata, vo
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_deepblu (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_deepblu (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"COSMIQ",
|
||||
@ -795,7 +834,8 @@ static int dc_filter_deepblu (dc_transport_t transport, const void *userdata, vo
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_oceans (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_oceans (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"S1",
|
||||
@ -808,15 +848,16 @@ static int dc_filter_oceans (dc_transport_t transport, const void *userdata, voi
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Not merged upstream yet
|
||||
static int dc_filter_garmin (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_divesoft (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const dc_usb_desc_t usbhid[] = {
|
||||
{0x091e, 0x2b2b}, // Garmin Descent Mk1
|
||||
static const char * const bluetooth[] = {
|
||||
"Freedom",
|
||||
"Liberty",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_USBSTORAGE) {
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usb);
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -914,10 +955,10 @@ dc_descriptor_get_transports (dc_descriptor_t *descriptor)
|
||||
}
|
||||
|
||||
int
|
||||
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata, void *params)
|
||||
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
if (descriptor == NULL || descriptor->filter == NULL || userdata == NULL)
|
||||
return 1;
|
||||
|
||||
return descriptor->filter (transport, userdata, params);
|
||||
return descriptor->filter (descriptor, transport, userdata);
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
#include "oceanic_atom2.h"
|
||||
#include "oceanic_veo250.h"
|
||||
#include "oceanic_vtpro.h"
|
||||
#include "pelagic_i330r.h"
|
||||
#include "mares_darwin.h"
|
||||
#include "mares_iconhd.h"
|
||||
#include "mares_nemo.h"
|
||||
@ -64,6 +65,7 @@
|
||||
#include "seac_screen.h"
|
||||
#include "deepblu_cosmiq.h"
|
||||
#include "oceans_s1.h"
|
||||
#include "divesoft_freedom.h"
|
||||
|
||||
// Not merged upstream yet
|
||||
#include "garmin.h"
|
||||
@ -164,6 +166,9 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
|
||||
case DC_FAMILY_OCEANIC_ATOM2:
|
||||
rc = oceanic_atom2_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
||||
break;
|
||||
case DC_FAMILY_PELAGIC_I330R:
|
||||
rc = pelagic_i330r_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
||||
break;
|
||||
case DC_FAMILY_MARES_NEMO:
|
||||
rc = mares_nemo_device_open (&device, context, iostream);
|
||||
break;
|
||||
@ -242,6 +247,9 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
|
||||
case DC_FAMILY_OCEANS_S1:
|
||||
rc = oceans_s1_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_DIVESOFT_FREEDOM:
|
||||
rc = divesoft_freedom_device_open (&device, context, iostream);
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
diverite_nitekq_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
diverite_nitekq_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
diverite_nitekq_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -49,7 +49,6 @@ struct diverite_nitekq_parser_t {
|
||||
double maxdepth;
|
||||
};
|
||||
|
||||
static dc_status_t diverite_nitekq_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t diverite_nitekq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -57,7 +56,6 @@ static dc_status_t diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract
|
||||
static const dc_parser_vtable_t diverite_nitekq_parser_vtable = {
|
||||
sizeof(diverite_nitekq_parser_t),
|
||||
DC_FAMILY_DIVERITE_NITEKQ,
|
||||
diverite_nitekq_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -69,7 +67,7 @@ static const dc_parser_vtable_t diverite_nitekq_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
diverite_nitekq_parser_t *parser = NULL;
|
||||
|
||||
@ -77,7 +75,7 @@ diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (diverite_nitekq_parser_t *) dc_parser_allocate (context, &diverite_nitekq_parser_vtable);
|
||||
parser = (diverite_nitekq_parser_t *) dc_parser_allocate (context, &diverite_nitekq_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -101,13 +99,6 @@ diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
diverite_nitekq_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -161,6 +152,7 @@ diverite_nitekq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, u
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = parser->he[flags] / 100.0;
|
||||
gasmix->oxygen = parser->o2[flags] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -264,13 +256,13 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
|
||||
// Time (seconds).
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Gas change
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
@ -282,7 +274,7 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
sample.depth = depth / 10.0;
|
||||
else
|
||||
sample.depth = depth * FEET / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
offset += 2;
|
||||
|
||||
if (type == 3) {
|
||||
@ -293,8 +285,9 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
if (offset + 1 > size)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
unsigned int ppo2 = data[offset];
|
||||
sample.ppo2 = ppo2 / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
|
||||
sample.ppo2.sensor = DC_SENSOR_NONE;
|
||||
sample.ppo2.value = ppo2 / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PPO2, &sample, userdata);
|
||||
offset++;
|
||||
}
|
||||
} else {
|
||||
|
||||
595
src/divesoft_freedom.c
Normal file
595
src/divesoft_freedom.c
Normal file
@ -0,0 +1,595 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2023 Jan Matoušek, Jef Driesen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "divesoft_freedom.h"
|
||||
#include "context-private.h"
|
||||
#include "device-private.h"
|
||||
#include "platform.h"
|
||||
#include "checksum.h"
|
||||
#include "array.h"
|
||||
#include "hdlc.h"
|
||||
|
||||
#define MAXDATA 256
|
||||
|
||||
#define HEADER_SIGNATURE_V1 0x45766944 // "DivE"
|
||||
#define HEADER_SIGNATURE_V2 0x45566944 // "DiVE"
|
||||
|
||||
#define HEADER_SIZE_V1 32
|
||||
#define HEADER_SIZE_V2 64
|
||||
|
||||
#define RECORD_SIZE 16
|
||||
#define FINGERPRINT_SIZE 20
|
||||
|
||||
#define INVALID 0xFFFFFFFF
|
||||
#define COMPRESSION 1
|
||||
#define DIRECTION 1
|
||||
#define NRECORDS 100
|
||||
|
||||
#define DEVICE_CCR_CU 1 // Liberty HW rev. 1.X
|
||||
#define DEVICE_FREEDOM 2 // Freedom HW rev. 2.X
|
||||
#define DEVICE_FREEDOM3 5 // Freedom HW rev. 3.X
|
||||
#define DEVICE_CCR_CU15 10 // Liberty HW rev. 2.X, Bluetooth enabled
|
||||
#define DEVICE_FREEDOM4 19 // Freedom HW rev. 4.X, Bluetooth enabled
|
||||
|
||||
typedef enum message_t {
|
||||
MSG_ECHO = 0,
|
||||
MSG_RESULT = 1,
|
||||
MSG_CONNECT = 2,
|
||||
MSG_CONNECTED = 3,
|
||||
MSG_VERSION = 4,
|
||||
MSG_VERSION_RSP = 5,
|
||||
MSG_DIVE_DATA = 64,
|
||||
MSG_DIVE_DATA_RSP = 65,
|
||||
MSG_DIVE_LIST = 66,
|
||||
MSG_DIVE_LIST_V1 = 67,
|
||||
MSG_DIVE_LIST_V2 = 71,
|
||||
} message_t;
|
||||
|
||||
typedef struct divesoft_freedom_device_t {
|
||||
dc_device_t base;
|
||||
dc_iostream_t *iostream;
|
||||
unsigned char fingerprint[FINGERPRINT_SIZE];
|
||||
unsigned int seqnum;
|
||||
} divesoft_freedom_device_t;
|
||||
|
||||
static dc_status_t divesoft_freedom_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||
static dc_status_t divesoft_freedom_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
||||
static dc_status_t divesoft_freedom_device_close (dc_device_t *device);
|
||||
|
||||
static const dc_device_vtable_t divesoft_freedom_device_vtable = {
|
||||
sizeof(divesoft_freedom_device_t),
|
||||
DC_FAMILY_DIVESOFT_FREEDOM,
|
||||
divesoft_freedom_device_set_fingerprint, /* set_fingerprint */
|
||||
NULL, /* read */
|
||||
NULL, /* write */
|
||||
NULL, /* dump */
|
||||
divesoft_freedom_device_foreach, /* foreach */
|
||||
NULL, /* timesync */
|
||||
divesoft_freedom_device_close, /* close */
|
||||
};
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_send (divesoft_freedom_device_t *device, message_t message, const unsigned char data[], size_t size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
size_t nbytes = 0, count = 0;
|
||||
while (1) {
|
||||
size_t len = size - nbytes;
|
||||
if (len > MAXDATA)
|
||||
len = MAXDATA;
|
||||
|
||||
unsigned int islast = nbytes + len == size;
|
||||
|
||||
unsigned char packet[6 + MAXDATA + 2] = {0};
|
||||
packet[0] = ((count & 0x0F) << 4) | (device->seqnum & 0x0F);
|
||||
packet[1] = 0x80 | (islast << 6);
|
||||
array_uint16_le_set (packet + 2, message);
|
||||
array_uint16_le_set (packet + 4, len);
|
||||
if (len) {
|
||||
memcpy (packet + 6, data + nbytes, len);
|
||||
}
|
||||
unsigned short crc = checksum_crc16r_ccitt (packet, len + 6, 0xFFFF, 0xFFFF);
|
||||
array_uint16_le_set (packet + 6 + len, crc);
|
||||
|
||||
HEXDUMP (abstract->context, DC_LOGLEVEL_DEBUG, "cmd", packet, 6 + len + 2);
|
||||
|
||||
status = dc_iostream_write (device->iostream, packet, 6 + len + 2, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the packet.");
|
||||
return status;
|
||||
}
|
||||
|
||||
nbytes += len;
|
||||
count++;
|
||||
|
||||
if (islast)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_recv (divesoft_freedom_device_t *device, dc_event_progress_t *progress, message_t *message, dc_buffer_t *buffer)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
unsigned int msg = INVALID;
|
||||
|
||||
unsigned int count = 0;
|
||||
while (1) {
|
||||
size_t len = 0;
|
||||
unsigned char packet[6 + MAXDATA + 2] = {0};
|
||||
status = dc_iostream_read (device->iostream, packet, sizeof(packet), &len);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the packet.");
|
||||
return status;
|
||||
}
|
||||
|
||||
HEXDUMP (abstract->context, DC_LOGLEVEL_DEBUG, "rcv", packet, len);
|
||||
|
||||
if (len < 8) {
|
||||
ERROR (abstract->context, "Unexpected packet length (" DC_PRINTF_SIZE ").", len);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
unsigned int seqnum = packet[0];
|
||||
unsigned int flags = packet[1];
|
||||
unsigned int type = array_uint16_le (packet + 2);
|
||||
unsigned int length = array_uint16_le (packet + 4);
|
||||
|
||||
unsigned int expected = ((count & 0x0F) << 4) | (device->seqnum & 0x0F);
|
||||
if (seqnum != expected) {
|
||||
ERROR (abstract->context, "Unexpected packet sequence number (%u %u).", seqnum, expected);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if ((flags & ~0x40) != 0) {
|
||||
ERROR (abstract->context, "Unexpected packet flags (%u).", flags);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (length != len - 8) {
|
||||
ERROR (abstract->context, "Unexpected packet length (%u " DC_PRINTF_SIZE ").", length, len - 8);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (msg == INVALID) {
|
||||
msg = type;
|
||||
} else if (msg != type) {
|
||||
ERROR (abstract->context, "Unexpected packet type (%u).", msg);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
unsigned short crc = array_uint16_le (packet + len - 2);
|
||||
unsigned short ccrc = checksum_crc16r_ccitt (packet, len - 2, 0xFFFF, 0xFFFF);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected packet checksum (%04x %04x).", crc, ccrc);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
if (progress) {
|
||||
progress->current += len - 8;
|
||||
// Limit the progress to the maximum size. This could happen if the
|
||||
// dive computer sends more data than requested for some reason.
|
||||
if (progress->current > progress->maximum) {
|
||||
WARNING (abstract->context, "Progress exceeds the maximum size.");
|
||||
progress->current = progress->maximum;
|
||||
}
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
|
||||
}
|
||||
|
||||
if (!dc_buffer_append (buffer, packet + 6, len - 8)) {
|
||||
ERROR (abstract->context, "Insufficient buffer space available.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
if (flags & 0x40)
|
||||
break;
|
||||
}
|
||||
|
||||
if (message)
|
||||
*message = msg;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_transfer (divesoft_freedom_device_t *device, dc_event_progress_t *progress, message_t cmd, const unsigned char data[], size_t size, message_t *msg, dc_buffer_t *buffer)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
if (device_is_cancelled (abstract))
|
||||
return DC_STATUS_CANCELLED;
|
||||
|
||||
device->seqnum++;
|
||||
|
||||
status = divesoft_freedom_send (device, cmd, data, size);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = divesoft_freedom_recv (device, progress, msg, buffer);
|
||||
if(status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive response.");
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_download (divesoft_freedom_device_t *device, message_t cmd, const unsigned char cdata[], size_t csize, unsigned char rdata[], size_t rsize)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
dc_buffer_t *buffer = dc_buffer_new (rsize);
|
||||
if (buffer == NULL) {
|
||||
ERROR (abstract->context, "Failed to allocate memory.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
message_t msg = MSG_ECHO;
|
||||
status = divesoft_freedom_transfer (device, NULL, cmd, cdata, csize, &msg, buffer);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to transfer the packet.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
if (msg != cmd + 1) {
|
||||
ERROR (abstract->context, "Unexpected response message (%u).", msg);
|
||||
status = DC_STATUS_PROTOCOL;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
size_t length = dc_buffer_get_size (buffer);
|
||||
if (length != rsize) {
|
||||
ERROR (abstract->context, "Unexpected response length (" DC_PRINTF_SIZE " " DC_PRINTF_SIZE ").", length, rsize);
|
||||
status = DC_STATUS_PROTOCOL;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
if (rsize) {
|
||||
memcpy (rdata, dc_buffer_get_data (buffer), rsize);
|
||||
}
|
||||
|
||||
error_free:
|
||||
dc_buffer_free (buffer);
|
||||
error_exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
divesoft_freedom_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
divesoft_freedom_device_t *device = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
device = (divesoft_freedom_device_t *) dc_device_allocate (context, &divesoft_freedom_device_vtable);
|
||||
if (device == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
device->iostream = NULL;
|
||||
memset(device->fingerprint, 0, sizeof(device->fingerprint));
|
||||
device->seqnum = 0;
|
||||
|
||||
// Setup the HDLC communication.
|
||||
status = dc_hdlc_open (&device->iostream, context, iostream, 244, 244);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to create the HDLC stream.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Set the serial communication protocol (115200 8N1).
|
||||
status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the terminal attributes.");
|
||||
goto error_free_hdlc;
|
||||
}
|
||||
|
||||
// Set the timeout for receiving data (3000ms).
|
||||
status = dc_iostream_set_timeout (device->iostream, 3000);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the timeout.");
|
||||
goto error_free_hdlc;
|
||||
}
|
||||
|
||||
// Initiate the connection with the dive computer.
|
||||
const char client[] = "libdivecomputer";
|
||||
unsigned char cmd_connect[2 + sizeof(client) - 1] = {0};
|
||||
array_uint16_le_set (cmd_connect, COMPRESSION);
|
||||
memcpy (cmd_connect + 2, client, sizeof(client) - 1);
|
||||
unsigned char rsp_connect[36] = {0};
|
||||
status = divesoft_freedom_download (device, MSG_CONNECT, cmd_connect, sizeof(cmd_connect), rsp_connect, sizeof(rsp_connect));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to connect to the device.");
|
||||
goto error_free_hdlc;
|
||||
}
|
||||
|
||||
DEBUG (context, "Connection: compression=%u, protocol=%u.%u, serial=%.16s",
|
||||
array_uint16_le (rsp_connect),
|
||||
rsp_connect[2], rsp_connect[3],
|
||||
rsp_connect + 4);
|
||||
|
||||
*out = (dc_device_t *) device;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free_hdlc:
|
||||
dc_iostream_close (device->iostream);
|
||||
error_free:
|
||||
dc_device_deallocate ((dc_device_t *) device);
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_device_close (dc_device_t *abstract)
|
||||
{
|
||||
divesoft_freedom_device_t *device = (divesoft_freedom_device_t *) abstract;
|
||||
|
||||
return dc_iostream_close (device->iostream);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
|
||||
{
|
||||
divesoft_freedom_device_t *device = (divesoft_freedom_device_t *) abstract;
|
||||
|
||||
if (size && size != sizeof (device->fingerprint))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (size)
|
||||
memcpy (device->fingerprint, data, sizeof (device->fingerprint));
|
||||
else
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
divesoft_freedom_device_t *device = (divesoft_freedom_device_t *) abstract;
|
||||
|
||||
// Enable progress notifications.
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
// Read the device information.
|
||||
unsigned char rsp_version[26] = {0};
|
||||
status = divesoft_freedom_download (device, MSG_VERSION, NULL, 0, rsp_version, sizeof(rsp_version));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the device information.");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
DEBUG (abstract->context, "Device: model=%u, hw=%u.%u, sw=%u.%u.%u.%u serial=%.16s",
|
||||
rsp_version[0],
|
||||
rsp_version[1], rsp_version[2],
|
||||
rsp_version[3], rsp_version[4], rsp_version[5],
|
||||
array_uint32_le (rsp_version + 6),
|
||||
rsp_version + 10);
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = rsp_version[0];
|
||||
devinfo.firmware = array_uint24_be (rsp_version + 3);
|
||||
devinfo.serial = array_convert_str2num (rsp_version + 10 + 5, 11);
|
||||
device_event_emit(abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
// Allocate memory for the dive list.
|
||||
dc_buffer_t *divelist = dc_buffer_new (0);
|
||||
if (divelist == NULL) {
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// Allocate memory for the download buffer.
|
||||
dc_buffer_t *buffer = dc_buffer_new (NRECORDS * (4 + FINGERPRINT_SIZE + HEADER_SIZE_V2));
|
||||
if (buffer == NULL) {
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free_divelist;
|
||||
}
|
||||
|
||||
// Record version and size.
|
||||
unsigned int version = 0;
|
||||
unsigned int headersize = 0;
|
||||
unsigned int recordsize = 0;
|
||||
|
||||
// Download the dive list.
|
||||
unsigned int ndives = 0;
|
||||
unsigned int total = 0;
|
||||
unsigned int maxsize = 0;
|
||||
unsigned int current = INVALID;
|
||||
while (1) {
|
||||
// Clear the buffer.
|
||||
dc_buffer_clear (buffer);
|
||||
|
||||
// Prepare the command.
|
||||
unsigned char cmd_list[6] = {0};
|
||||
array_uint32_le_set (cmd_list, current);
|
||||
cmd_list[4] = DIRECTION;
|
||||
cmd_list[5] = NRECORDS;
|
||||
|
||||
// Download the dive list records.
|
||||
message_t msg_list = MSG_ECHO;
|
||||
status = divesoft_freedom_transfer (device, &progress, MSG_DIVE_LIST, cmd_list, sizeof(cmd_list), &msg_list, buffer);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to download the dive list.");
|
||||
goto error_free_buffer;
|
||||
}
|
||||
|
||||
// Check the response message type.
|
||||
if (msg_list != MSG_DIVE_LIST_V1 && msg_list != MSG_DIVE_LIST_V2) {
|
||||
ERROR (abstract->context, "Unexpected response message (%u).", msg_list);
|
||||
status = DC_STATUS_PROTOCOL;
|
||||
goto error_free_buffer;
|
||||
}
|
||||
|
||||
// Store/check the version.
|
||||
if (version == 0) {
|
||||
version = msg_list;
|
||||
headersize = version == MSG_DIVE_LIST_V1 ?
|
||||
HEADER_SIZE_V1 : HEADER_SIZE_V2;
|
||||
recordsize = 4 + FINGERPRINT_SIZE + headersize;
|
||||
} else if (version != msg_list) {
|
||||
ERROR (abstract->context, "Unexpected response message (%u).", msg_list);
|
||||
status = DC_STATUS_PROTOCOL;
|
||||
goto error_free_buffer;
|
||||
}
|
||||
|
||||
const unsigned char *data = dc_buffer_get_data (buffer);
|
||||
size_t size = dc_buffer_get_size (buffer);
|
||||
|
||||
// Process the records.
|
||||
size_t offset = 0, count = 0;
|
||||
while (offset + recordsize <= size) {
|
||||
// Get the record data.
|
||||
unsigned int handle = array_uint32_le (data + offset);
|
||||
const unsigned char *fingerprint = data + offset + 4;
|
||||
const unsigned char *header = data + offset + 4 + FINGERPRINT_SIZE;
|
||||
|
||||
// Check the fingerprint data.
|
||||
if (memcmp (device->fingerprint, fingerprint, sizeof(device->fingerprint)) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the length of the dive.
|
||||
unsigned int nrecords = version == MSG_DIVE_LIST_V1 ?
|
||||
array_uint32_le (header + 16) & 0x3FFFF :
|
||||
array_uint32_le (header + 20);
|
||||
unsigned int length = headersize + nrecords * RECORD_SIZE;
|
||||
|
||||
// Calculate the total and maximum size.
|
||||
if (length > maxsize)
|
||||
maxsize = length;
|
||||
total += length;
|
||||
|
||||
// Set the handle for the next request.
|
||||
current = handle;
|
||||
|
||||
offset += recordsize;
|
||||
count++;
|
||||
ndives++;
|
||||
}
|
||||
|
||||
// Append the records to the dive list buffer.
|
||||
if (!dc_buffer_append (divelist, data, count * recordsize)) {
|
||||
ERROR (abstract->context, "Insufficient buffer space available.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free_buffer;
|
||||
}
|
||||
|
||||
// Stop downloading if there are no more records.
|
||||
if (count < NRECORDS)
|
||||
break;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.maximum = progress.current + total;
|
||||
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
// Reserve memory for the largest dive.
|
||||
dc_buffer_reserve (buffer, maxsize);
|
||||
|
||||
const unsigned char *data = dc_buffer_get_data (divelist);
|
||||
size_t size = dc_buffer_get_size (divelist);
|
||||
|
||||
size_t offset = 0;
|
||||
while (offset + recordsize <= size) {
|
||||
// Get the record data.
|
||||
unsigned int handle = array_uint32_le (data + offset);
|
||||
const unsigned char *fingerprint = data + offset + 4;
|
||||
const unsigned char *header = data + offset + 4 + FINGERPRINT_SIZE;
|
||||
|
||||
// Get the length of the dive.
|
||||
unsigned int nrecords = version == MSG_DIVE_LIST_V1 ?
|
||||
array_uint32_le (header + 16) & 0x3FFFF :
|
||||
array_uint32_le (header + 20);
|
||||
unsigned int length = headersize + nrecords * RECORD_SIZE;
|
||||
|
||||
// Clear the buffer.
|
||||
dc_buffer_clear (buffer);
|
||||
|
||||
// Prepare the command.
|
||||
unsigned char cmd_dive[12] = {0};
|
||||
array_uint32_le_set (cmd_dive + 0, handle);
|
||||
array_uint32_le_set (cmd_dive + 4, 0);
|
||||
array_uint32_le_set (cmd_dive + 8, length);
|
||||
|
||||
// Download the dive.
|
||||
message_t msg_dive = MSG_ECHO;
|
||||
status = divesoft_freedom_transfer (device, &progress, MSG_DIVE_DATA, cmd_dive, sizeof(cmd_dive), &msg_dive, buffer);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to download the dive.");
|
||||
goto error_free_buffer;
|
||||
}
|
||||
|
||||
// Check the response message type.
|
||||
if (msg_dive != MSG_DIVE_DATA_RSP) {
|
||||
ERROR (abstract->context, "Unexpected response message (%u).", msg_dive);
|
||||
status = DC_STATUS_PROTOCOL;
|
||||
goto error_free_buffer;
|
||||
}
|
||||
|
||||
// Verify both dive headers are identical.
|
||||
if (dc_buffer_get_size (buffer) < headersize ||
|
||||
memcmp (header, dc_buffer_get_data (buffer), headersize) != 0) {
|
||||
ERROR (abstract->context, "Unexpected profile header.");
|
||||
status = DC_STATUS_PROTOCOL;
|
||||
goto error_free_buffer;
|
||||
}
|
||||
|
||||
if (callback && !callback (dc_buffer_get_data(buffer), dc_buffer_get_size(buffer), fingerprint, sizeof (device->fingerprint), userdata)) {
|
||||
break;
|
||||
}
|
||||
|
||||
offset += recordsize;
|
||||
}
|
||||
|
||||
error_free_buffer:
|
||||
dc_buffer_free (buffer);
|
||||
error_free_divelist:
|
||||
dc_buffer_free (divelist);
|
||||
error_exit:
|
||||
return status;
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2017 Jef Driesen
|
||||
* 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
|
||||
@ -19,33 +19,25 @@
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef DC_DESCRIPTOR_PRIVATE_H
|
||||
#define DC_DESCRIPTOR_PRIVATE_H
|
||||
#ifndef DIVESOFT_FREEDOM_H
|
||||
#define DIVESOFT_FREEDOM_H
|
||||
|
||||
#include <libdivecomputer/descriptor.h>
|
||||
|
||||
// Oh joy. Windows is some truly horrendously broken crap
|
||||
#undef interface
|
||||
#include <libdivecomputer/context.h>
|
||||
#include <libdivecomputer/iostream.h>
|
||||
#include <libdivecomputer/device.h>
|
||||
#include <libdivecomputer/parser.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct dc_usb_desc_t {
|
||||
unsigned short vid;
|
||||
unsigned short pid;
|
||||
} dc_usb_desc_t;
|
||||
dc_status_t
|
||||
divesoft_freedom_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
typedef struct dc_usb_params_t {
|
||||
unsigned int interface;
|
||||
unsigned char endpoint_in;
|
||||
unsigned char endpoint_out;
|
||||
} dc_usb_params_t;
|
||||
|
||||
int
|
||||
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata, void *params);
|
||||
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 /* DC_DESCRIPTOR_PRIVATE_H */
|
||||
#endif /* DIVESOFT_FREEDOM_H */
|
||||
1036
src/divesoft_freedom_parser.c
Normal file
1036
src/divesoft_freedom_parser.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -29,6 +29,7 @@
|
||||
#include "platform.h"
|
||||
#include "checksum.h"
|
||||
#include "array.h"
|
||||
#include "packet.h"
|
||||
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &divesystem_idive_device_vtable)
|
||||
|
||||
@ -102,6 +103,7 @@ typedef struct divesystem_idive_device_t {
|
||||
static dc_status_t divesystem_idive_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||
static dc_status_t divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
||||
static dc_status_t divesystem_idive_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime);
|
||||
static dc_status_t divesystem_idive_device_close (dc_device_t *abstract);
|
||||
|
||||
static const dc_device_vtable_t divesystem_idive_device_vtable = {
|
||||
sizeof(divesystem_idive_device_t),
|
||||
@ -112,7 +114,7 @@ static const dc_device_vtable_t divesystem_idive_device_vtable = {
|
||||
NULL, /* dump */
|
||||
divesystem_idive_device_foreach, /* foreach */
|
||||
divesystem_idive_device_timesync, /* timesync */
|
||||
NULL /* close */
|
||||
divesystem_idive_device_close /* close */
|
||||
};
|
||||
|
||||
static const divesystem_idive_commands_t idive = {
|
||||
@ -152,6 +154,7 @@ divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, dc_iostr
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
divesystem_idive_device_t *device = NULL;
|
||||
dc_transport_t transport = dc_iostream_get_transport (iostream);
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
@ -164,22 +167,32 @@ divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, dc_iostr
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
device->iostream = iostream;
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
device->model = model;
|
||||
|
||||
// Create the packet stream.
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
status = dc_packet_open (&device->iostream, context, iostream, 244, 244);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to create the packet stream.");
|
||||
goto error_free;
|
||||
}
|
||||
} else {
|
||||
device->iostream = iostream;
|
||||
}
|
||||
|
||||
// Set the serial communication protocol (115200 8N1).
|
||||
status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the terminal attributes.");
|
||||
goto error_free;
|
||||
goto error_free_iostream;
|
||||
}
|
||||
|
||||
// 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;
|
||||
goto error_free_iostream;
|
||||
}
|
||||
|
||||
// Make sure everything is in a sane state.
|
||||
@ -190,11 +203,27 @@ divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, dc_iostr
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free_iostream:
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
dc_iostream_close (device->iostream);
|
||||
}
|
||||
error_free:
|
||||
dc_device_deallocate ((dc_device_t *) device);
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesystem_idive_device_close (dc_device_t *abstract)
|
||||
{
|
||||
divesystem_idive_device_t *device = (divesystem_idive_device_t *) abstract;
|
||||
|
||||
// Close the packet stream.
|
||||
if (dc_iostream_get_transport (device->iostream) == DC_TRANSPORT_BLE) {
|
||||
return dc_iostream_close (device->iostream);
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesystem_idive_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
|
||||
@ -231,7 +260,7 @@ divesystem_idive_send (divesystem_idive_device_t *device, const unsigned char co
|
||||
packet[0] = START;
|
||||
packet[1] = csize;
|
||||
memcpy(packet + 2, command, csize);
|
||||
crc = checksum_crc16_ccitt (packet, csize + 2, 0xffff);
|
||||
crc = checksum_crc16_ccitt (packet, csize + 2, 0xffff, 0x0000);
|
||||
packet[csize + 2] = (crc >> 8) & 0xFF;
|
||||
packet[csize + 3] = (crc ) & 0xFF;
|
||||
|
||||
@ -292,7 +321,7 @@ divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answe
|
||||
|
||||
// Verify the checksum.
|
||||
unsigned short crc = array_uint16_be (packet + len + 2);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (packet, len + 2, 0xffff);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (packet, len + 2, 0xffff, 0x0000);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected packet checksum.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
divesystem_idive_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
divesystem_idive_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -58,6 +58,9 @@
|
||||
#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_gasmix_t {
|
||||
@ -89,7 +92,6 @@ struct divesystem_idive_parser_t {
|
||||
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_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);
|
||||
@ -97,7 +99,6 @@ static dc_status_t divesystem_idive_parser_samples_foreach (dc_parser_t *abstrac
|
||||
static const dc_parser_vtable_t divesystem_idive_parser_vtable = {
|
||||
sizeof(divesystem_idive_parser_t),
|
||||
DC_FAMILY_DIVESYSTEM_IDIVE,
|
||||
divesystem_idive_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -109,7 +110,7 @@ static const dc_parser_vtable_t divesystem_idive_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
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_t *parser = NULL;
|
||||
|
||||
@ -117,7 +118,7 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, unsign
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (divesystem_idive_parser_t *) dc_parser_allocate (context, &divesystem_idive_parser_vtable);
|
||||
parser = (divesystem_idive_parser_t *) dc_parser_allocate (context, &divesystem_idive_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -156,35 +157,6 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, unsign
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
parser->algorithm = INVALID;
|
||||
parser->gf_low = INVALID;
|
||||
parser->gf_high = INVALID;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -317,6 +289,7 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = parser->gasmix[flags].helium / 100.0;
|
||||
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -331,6 +304,7 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
tank->beginpressure = parser->tank[flags].beginpressure;
|
||||
tank->endpressure = parser->tank[flags].endpressure;
|
||||
tank->gasmix = DC_GASMIX_UNKNOWN;
|
||||
tank->usage = DC_TANK_USAGE_NONE;
|
||||
break;
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
if (ISIX3M(parser->model)) {
|
||||
@ -439,6 +413,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
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 apos4 = 0;
|
||||
@ -467,27 +442,37 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
while (offset + samplesize <= size) {
|
||||
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).
|
||||
unsigned int timestamp = array_uint32_le (data + offset + 2);
|
||||
if (timestamp <= time) {
|
||||
ERROR (abstract->context, "Timestamp moved backwards.");
|
||||
if (timestamp <= time && time != 0) {
|
||||
ERROR (abstract->context, "Timestamp moved backwards (%u %u).", timestamp, time);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
time = timestamp;
|
||||
sample.time = timestamp;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = timestamp * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
unsigned int depth = array_uint16_le (data + offset + 6);
|
||||
if (maxdepth < depth)
|
||||
maxdepth = depth;
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Temperature (Celsius).
|
||||
signed int temperature = (signed short) array_uint16_le (data + offset + 8);
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
// Dive mode
|
||||
unsigned int mode = data[offset + 18];
|
||||
@ -521,7 +506,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
if (mode == SCR || mode == CCR) {
|
||||
unsigned int setpoint = array_uint16_le (data + offset + 19);
|
||||
sample.setpoint = setpoint / 1000.0;
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||
}
|
||||
|
||||
// Gaschange.
|
||||
@ -548,7 +533,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
}
|
||||
|
||||
sample.gasmix = i;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
o2_previous = o2;
|
||||
he_previous = he;
|
||||
}
|
||||
@ -566,18 +551,20 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
if (decostop) {
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = decostop / 10.0;
|
||||
sample.deco.time = apos4 ? decotime : tts;
|
||||
sample.deco.time = decotime;
|
||||
sample.deco.tts = tts;
|
||||
} else {
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.depth = 0.0;
|
||||
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
|
||||
unsigned int cns = array_uint16_le (data + offset + 29);
|
||||
sample.cns = cns / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata);
|
||||
|
||||
// Tank Pressure
|
||||
if (samplesize == SZ_SAMPLE_IX3M_APOS4) {
|
||||
@ -598,7 +585,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = 0;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
} else {
|
||||
// Get the index of the tank.
|
||||
if (id != tank_previous) {
|
||||
@ -628,10 +615,20 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
if (tank_idx < ntanks) {
|
||||
sample.pressure.tank = tank_idx;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
@ -85,8 +85,9 @@ dc_field_get(dc_field_cache_t *cache, dc_field_type_t type, unsigned int flags,
|
||||
case DC_FIELD_AVGDEPTH:
|
||||
return DC_FIELD_VALUE(*cache, value, AVGDEPTH);
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
case DC_FIELD_TANK_COUNT:
|
||||
return DC_FIELD_VALUE(*cache, value, GASMIX_COUNT);
|
||||
case DC_FIELD_TANK_COUNT:
|
||||
return DC_FIELD_VALUE(*cache, value, TANK_COUNT);
|
||||
case DC_FIELD_GASMIX:
|
||||
if (flags >= MAXGASES)
|
||||
break;
|
||||
|
||||
@ -14,6 +14,7 @@ typedef struct dc_field_cache {
|
||||
double ATMOSPHERIC;
|
||||
dc_divemode_t DIVEMODE;
|
||||
unsigned int GASMIX_COUNT;
|
||||
unsigned int TANK_COUNT;
|
||||
dc_salinity_t SALINITY;
|
||||
dc_gasmix_t GASMIX[MAXGASES];
|
||||
|
||||
@ -26,6 +27,7 @@ typedef struct dc_field_cache {
|
||||
// dc_tank_t TANK[MAXGASES]
|
||||
// but that's for later
|
||||
dc_tankinfo_t tankinfo[MAXGASES];
|
||||
dc_tank_usage_t tankusage[MAXGASES];
|
||||
double tanksize[MAXGASES];
|
||||
double tankworkingpressure[MAXGASES];
|
||||
|
||||
|
||||
68
src/garmin.c
68
src/garmin.c
@ -52,6 +52,7 @@ typedef struct garmin_device_t {
|
||||
dc_device_t base;
|
||||
dc_iostream_t *iostream;
|
||||
unsigned char fingerprint[FIT_NAME_SIZE];
|
||||
unsigned int model;
|
||||
#ifdef HAVE_LIBMTP
|
||||
unsigned char use_mtp;
|
||||
LIBMTP_mtpdevice_t *mtp_device;
|
||||
@ -92,6 +93,7 @@ garmin_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *ios
|
||||
// Set the default values.
|
||||
device->iostream = iostream;
|
||||
memset(device->fingerprint, 0, sizeof(device->fingerprint));
|
||||
device->model = model;
|
||||
|
||||
#ifdef HAVE_LIBMTP
|
||||
// for a Descent Mk2/Mk2i, we have to use MTP to access its storage;
|
||||
@ -99,7 +101,6 @@ 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
|
||||
device->use_mtp = (model == (0x0FFF & DESCENT_MK2));
|
||||
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
|
||||
|
||||
*out = (dc_device_t *) device;
|
||||
@ -136,6 +137,17 @@ garmin_device_close (dc_device_t *abstract)
|
||||
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 {
|
||||
int nr, allocated;
|
||||
struct fit_file *array;
|
||||
@ -173,8 +185,8 @@ static int name_cmp(const void *_a, const void *_b)
|
||||
const char *a_name = a->name;
|
||||
const char *b_name = b->name;
|
||||
|
||||
char a_buffer[FIT_NAME_SIZE];
|
||||
char b_buffer[FIT_NAME_SIZE];
|
||||
char a_buffer[FILE_NAME_SIZE];
|
||||
char b_buffer[FILE_NAME_SIZE];
|
||||
|
||||
if (strlen(a_name) == 12) {
|
||||
parse_short_name(a_name, a_buffer);
|
||||
@ -200,19 +212,16 @@ static int
|
||||
check_filename(dc_device_t *abstract, const char *name)
|
||||
{
|
||||
int len = strlen(name);
|
||||
const char *explain = NULL;
|
||||
|
||||
DEBUG(abstract->context, " %s", name);
|
||||
|
||||
if (len < 5)
|
||||
explain = "name too short";
|
||||
if (len >= FIT_NAME_SIZE)
|
||||
explain = "name too long";
|
||||
return 0;
|
||||
if (len >= FILE_NAME_SIZE)
|
||||
return 0;
|
||||
if (strncasecmp(name + len - 4, ".FIT", 4))
|
||||
explain = "name lacks FIT suffix";
|
||||
return 0;
|
||||
|
||||
DEBUG(abstract->context, " %s - %s", name, explain ? explain : "adding to list");
|
||||
return explain == NULL;
|
||||
DEBUG(abstract->context, " %s - adding to list", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
@ -243,8 +252,8 @@ add_name(struct file_list *files, const char *name, unsigned int mtp_id)
|
||||
* will zero-pad the end of the result buffer.
|
||||
*/
|
||||
struct fit_file *entry = files->array + files->nr++;
|
||||
strncpy(entry->name, name, FIT_NAME_SIZE);
|
||||
entry->name[FIT_NAME_SIZE] = 0; // ensure it's null-terminated
|
||||
strncpy(entry->name, name, FILE_NAME_SIZE);
|
||||
entry->name[FILE_NAME_SIZE] = 0; // ensure it's null-terminated
|
||||
entry->mtp_id = mtp_id;
|
||||
}
|
||||
|
||||
@ -321,12 +330,16 @@ mtp_get_file_list(dc_device_t *abstract, struct file_list *files)
|
||||
for (i = 0; i < numrawdevices; i++) {
|
||||
LIBMTP_devicestorage_t *storage;
|
||||
// we only want to read from a Garmin Descent Mk2 device at this point
|
||||
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)) {
|
||||
if (rawdevices[i].device_entry.vendor_id != GARMIN_VENDOR) {
|
||||
DEBUG(abstract->context, "Garmin/mtp: skipping raw device %04x/%04x",
|
||||
rawdevices[i].device_entry.vendor_id, rawdevices[i].device_entry.product_id);
|
||||
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]);
|
||||
if (device->mtp_device == NULL) {
|
||||
DEBUG(abstract->context, "Garmin/mtp: unable to open raw device %d", i);
|
||||
@ -407,7 +420,7 @@ read_file(char *pathname, int pathlen, const char *name, dc_buffer_t *file)
|
||||
int fd, rc;
|
||||
|
||||
pathname[pathlen] = '/';
|
||||
memcpy(pathname+pathlen+1, name, FIT_NAME_SIZE);
|
||||
memcpy(pathname+pathlen+1, name, FILE_NAME_SIZE);
|
||||
fd = open(pathname, O_RDONLY | O_BINARY);
|
||||
|
||||
if (fd < 0)
|
||||
@ -438,7 +451,6 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
garmin_device_t *device = (garmin_device_t *) abstract;
|
||||
dc_parser_t *parser;
|
||||
char pathname[PATH_MAX];
|
||||
char pathname_input[PATH_MAX];
|
||||
size_t pathlen;
|
||||
@ -466,7 +478,7 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
|
||||
// The actual dives are under the "Garmin/Activity/" directory
|
||||
// as FIT files, with names like "2018-08-20-10-23-30.fit".
|
||||
// Make sure our buffer is big enough.
|
||||
if (pathlen + strlen("/Garmin/Activity/") + FIT_NAME_SIZE + 2 > PATH_MAX) {
|
||||
if (pathlen + strlen("/Garmin/Activity/") + FILE_NAME_SIZE + 2 > PATH_MAX) {
|
||||
ERROR (abstract->context, "Invalid Garmin base directory '%s'", pathname_input);
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
@ -529,16 +541,12 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
|
||||
free(files.array);
|
||||
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_p = &devinfo;
|
||||
for (int i = 0; i < files.nr; i++) {
|
||||
const char *name = files.array[i].name;
|
||||
dc_parser_t *parser;
|
||||
const unsigned char *data;
|
||||
unsigned int size;
|
||||
short is_dive = 0;
|
||||
@ -564,7 +572,14 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
|
||||
data = dc_buffer_get_data(file);
|
||||
size = dc_buffer_get_size(file);
|
||||
|
||||
is_dive = garmin_parser_is_dive(parser, data, size, devinfo_p);
|
||||
status = garmin_parser_create(&parser, abstract->context, data, size);
|
||||
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) {
|
||||
// first time we came through here, let's emit the
|
||||
// devinfo and vendor events
|
||||
@ -573,6 +588,7 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
|
||||
}
|
||||
if (!is_dive) {
|
||||
DEBUG(abstract->context, "decided %s isn't a dive.", name);
|
||||
dc_parser_destroy(parser);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -581,10 +597,10 @@ garmin_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
|
||||
|
||||
progress.current++;
|
||||
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
|
||||
dc_parser_destroy(parser);
|
||||
}
|
||||
|
||||
free(files.array);
|
||||
dc_parser_destroy(parser);
|
||||
dc_buffer_free(file);
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
dc_status_t
|
||||
garmin_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
garmin_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
// we need to be able to call into the parser to check if the
|
||||
// files that we find are actual dives
|
||||
int
|
||||
garmin_parser_is_dive (dc_parser_t *abstract, const unsigned char *data, unsigned int size, dc_event_devinfo_t *devinfo_p);
|
||||
garmin_parser_is_dive (dc_parser_t *abstract, dc_event_devinfo_t *devinfo_p);
|
||||
|
||||
// The dive names are of the form "2018-08-20-10-23-30.fit"
|
||||
// With the terminating zero, that's 24 bytes.
|
||||
@ -49,11 +49,6 @@ garmin_parser_is_dive (dc_parser_t *abstract, const unsigned char *data, unsigne
|
||||
// special fixed header in the parser data too.
|
||||
#define FIT_NAME_SIZE 24
|
||||
|
||||
struct fit_file {
|
||||
char name[FIT_NAME_SIZE + 1];
|
||||
unsigned int mtp_id;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
#include "array.h"
|
||||
#include "field-cache.h"
|
||||
|
||||
#define MAXFIELDS 128
|
||||
#define MAXFIELDS 160
|
||||
|
||||
struct msg_desc;
|
||||
|
||||
@ -38,7 +38,7 @@ struct msg_desc;
|
||||
struct type_desc {
|
||||
const char *msg_name;
|
||||
const struct msg_desc *msg_desc;
|
||||
unsigned char nrfields;
|
||||
unsigned char nrfields, devfields;
|
||||
unsigned char fields[MAXFIELDS][3];
|
||||
};
|
||||
|
||||
@ -65,13 +65,14 @@ struct garmin_sensor {
|
||||
struct record_data {
|
||||
unsigned int pending;
|
||||
unsigned int time;
|
||||
unsigned int timestamp;
|
||||
|
||||
// RECORD_DECO
|
||||
int stop_time;
|
||||
double ceiling;
|
||||
|
||||
// RECORD_GASMIX
|
||||
int index, gas_status, gas_type;
|
||||
int index, gas_status;
|
||||
dc_gasmix_t gasmix;
|
||||
|
||||
// RECORD_EVENT
|
||||
@ -128,7 +129,7 @@ typedef struct garmin_parser_t {
|
||||
unsigned int setpoint_low_cbar, setpoint_high_cbar;
|
||||
unsigned int setpoint_low_switch_depth_mm, setpoint_high_switch_depth_mm;
|
||||
unsigned int setpoint_low_switch_mode, setpoint_high_switch_mode;
|
||||
dc_tankinfo_t *current_tankinfo;
|
||||
dc_usage_t current_gasmix_usage;
|
||||
} dive;
|
||||
|
||||
// I count nine (!) different GPS fields Hmm.
|
||||
@ -231,27 +232,27 @@ static void garmin_event(struct garmin_parser_t *garmin,
|
||||
|
||||
if (!sample.event.name)
|
||||
return;
|
||||
garmin->callback(DC_SAMPLE_EVENT, sample, garmin->userdata);
|
||||
garmin->callback(DC_SAMPLE_EVENT, &sample, garmin->userdata);
|
||||
return;
|
||||
|
||||
case 57:
|
||||
sample.gasmix = data;
|
||||
garmin->callback(DC_SAMPLE_GASMIX, sample, garmin->userdata);
|
||||
garmin->callback(DC_SAMPLE_GASMIX, &sample, garmin->userdata);
|
||||
|
||||
dc_tankinfo_t *tankinfo = &garmin->cache.tankinfo[data];
|
||||
if (!garmin->dive.current_tankinfo || (*tankinfo & DC_TANKINFO_CC_DILUENT) != (*garmin->dive.current_tankinfo & DC_TANKINFO_CC_DILUENT)) {
|
||||
dc_usage_t gasmix_usage = garmin->cache.GASMIX[data].usage;
|
||||
if (gasmix_usage != garmin->dive.current_gasmix_usage) {
|
||||
dc_sample_value_t sample2 = {0};
|
||||
sample2.event.type = SAMPLE_EVENT_STRING;
|
||||
if (*tankinfo & DC_TANKINFO_CC_DILUENT) {
|
||||
if (gasmix_usage == DC_USAGE_DILUENT) {
|
||||
sample2.event.name = "Switched to closed circuit";
|
||||
} else {
|
||||
sample2.event.name = "Switched to open circuit bailout";
|
||||
}
|
||||
sample2.event.flags = 2 << SAMPLE_FLAGS_SEVERITY_SHIFT;
|
||||
|
||||
garmin->callback(DC_SAMPLE_EVENT, sample2, garmin->userdata);
|
||||
garmin->callback(DC_SAMPLE_EVENT, &sample2, garmin->userdata);
|
||||
|
||||
garmin->dive.current_tankinfo = tankinfo;
|
||||
garmin->dive.current_gasmix_usage = gasmix_usage;
|
||||
}
|
||||
|
||||
return;
|
||||
@ -278,17 +279,7 @@ static void flush_pending_record(struct garmin_parser_t *garmin)
|
||||
int index = record->index;
|
||||
if (enabled && index < MAXGASES) {
|
||||
DC_ASSIGN_IDX(garmin->cache, GASMIX, index, record->gasmix);
|
||||
if (index + 1 > garmin->cache.GASMIX_COUNT) {
|
||||
DC_ASSIGN_FIELD(garmin->cache, GASMIX_COUNT, index + 1);
|
||||
garmin->cache.initialized |= 1 << DC_FIELD_TANK_COUNT;
|
||||
}
|
||||
|
||||
dc_tankinfo_t tankinfo = DC_TANKINFO_METRIC;
|
||||
if (record->gas_type == 1) {
|
||||
tankinfo |= DC_TANKINFO_CC_DILUENT;
|
||||
}
|
||||
garmin->cache.tankinfo[index] = tankinfo;
|
||||
garmin->cache.initialized |= 1 << DC_FIELD_TANK;
|
||||
DC_ASSIGN_FIELD(garmin->cache, GASMIX_COUNT, index + 1);
|
||||
}
|
||||
}
|
||||
if (pending & RECORD_DEVICE_INFO && record->device_index == 0) {
|
||||
@ -323,7 +314,7 @@ static void flush_pending_record(struct garmin_parser_t *garmin)
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.time = record->stop_time;
|
||||
sample.deco.depth = record->ceiling;
|
||||
garmin->callback(DC_SAMPLE_DECO, sample, garmin->userdata);
|
||||
garmin->callback(DC_SAMPLE_DECO, &sample, garmin->userdata);
|
||||
}
|
||||
|
||||
if (pending & RECORD_EVENT) {
|
||||
@ -336,19 +327,19 @@ static void flush_pending_record(struct garmin_parser_t *garmin)
|
||||
|
||||
sample.pressure.tank = find_tank_index(garmin, record->sensor);
|
||||
sample.pressure.value = record->pressure / 100.0;
|
||||
garmin->callback(DC_SAMPLE_PRESSURE, sample, garmin->userdata);
|
||||
garmin->callback(DC_SAMPLE_PRESSURE, &sample, garmin->userdata);
|
||||
}
|
||||
|
||||
if (pending & RECORD_SETPOINT_CHANGE) {
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
sample.setpoint = record->setpoint_actual_cbar / 100.0;
|
||||
garmin->callback(DC_SAMPLE_SETPOINT, sample, garmin->userdata);
|
||||
garmin->callback(DC_SAMPLE_SETPOINT, &sample, garmin->userdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t garmin_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t garmin_parser_set_data (garmin_parser_t *garmin, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t garmin_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t garmin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t garmin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -356,7 +347,6 @@ static dc_status_t garmin_parser_samples_foreach (dc_parser_t *abstract, dc_samp
|
||||
static const dc_parser_vtable_t garmin_parser_vtable = {
|
||||
sizeof(garmin_parser_t),
|
||||
DC_FAMILY_GARMIN,
|
||||
garmin_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -367,7 +357,7 @@ static const dc_parser_vtable_t garmin_parser_vtable = {
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
garmin_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
garmin_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
garmin_parser_t *parser = NULL;
|
||||
|
||||
@ -375,39 +365,64 @@ garmin_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (garmin_parser_t *) dc_parser_allocate (context, &garmin_parser_vtable);
|
||||
parser = (garmin_parser_t *) dc_parser_allocate (context, &garmin_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
garmin_parser_set_data(parser, data, size);
|
||||
|
||||
*out = (dc_parser_t *) parser;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define DECLARE_FIT_TYPE(name, ctype, inval) \
|
||||
/*
|
||||
* We really shouldn't use array_uint_be/le, since they
|
||||
* can't deal with 64-bit types.
|
||||
*
|
||||
* But we've not actually seen any yet, so..
|
||||
*/
|
||||
static inline unsigned long long garmin_value(struct garmin_parser_t *g, const unsigned char *p, unsigned int type_size)
|
||||
{
|
||||
if (g->is_big_endian)
|
||||
return array_uint_be(p, type_size);
|
||||
else
|
||||
return array_uint_le(p, type_size);
|
||||
}
|
||||
|
||||
#define FMTSIZE 64
|
||||
|
||||
#define DECLARE_FIT_TYPE(name, ctype, inval, fmt) \
|
||||
typedef ctype name; \
|
||||
static const name name##_INVAL = inval
|
||||
static const name name##_INVAL = inval; \
|
||||
static name name##_VALUE(garmin_parser_t *g, const void *p) \
|
||||
{ return (name) garmin_value(g, p, sizeof(name)); } \
|
||||
static void name##_FORMAT(name val, char *buf) \
|
||||
{ snprintf(buf, FMTSIZE, fmt, val); }
|
||||
|
||||
DECLARE_FIT_TYPE(ENUM, unsigned char, 0xff);
|
||||
DECLARE_FIT_TYPE(UINT8, unsigned char, 0xff);
|
||||
DECLARE_FIT_TYPE(UINT16, unsigned short, 0xffff);
|
||||
DECLARE_FIT_TYPE(UINT32, unsigned int, 0xffffffff);
|
||||
DECLARE_FIT_TYPE(UINT64, unsigned long long, 0xffffffffffffffffull);
|
||||
DECLARE_FIT_TYPE(ENUM, unsigned char, 0xff, "%u");
|
||||
DECLARE_FIT_TYPE(UINT8, unsigned char, 0xff, "%u");
|
||||
DECLARE_FIT_TYPE(UINT16, unsigned short, 0xffff, "%u");
|
||||
DECLARE_FIT_TYPE(UINT32, unsigned int, 0xffffffff, "%u");
|
||||
DECLARE_FIT_TYPE(UINT64, unsigned long long, 0xffffffffffffffffull, "%llu");
|
||||
|
||||
DECLARE_FIT_TYPE(UINT8Z, unsigned char, 0);
|
||||
DECLARE_FIT_TYPE(UINT16Z, unsigned short, 0);
|
||||
DECLARE_FIT_TYPE(UINT32Z, unsigned int, 0);
|
||||
DECLARE_FIT_TYPE(UINT8Z, unsigned char, 0, "%u");
|
||||
DECLARE_FIT_TYPE(UINT16Z, unsigned short, 0, "%u");
|
||||
DECLARE_FIT_TYPE(UINT32Z, unsigned int, 0, "%u");
|
||||
|
||||
DECLARE_FIT_TYPE(SINT8, signed char, 0x7f);
|
||||
DECLARE_FIT_TYPE(SINT16, signed short, 0x7fff);
|
||||
DECLARE_FIT_TYPE(SINT32, signed int, 0x7fffffff);
|
||||
DECLARE_FIT_TYPE(SINT64, signed long long, 0x7fffffffffffffffll);
|
||||
DECLARE_FIT_TYPE(SINT8, signed char, 0x7f, "%d");
|
||||
DECLARE_FIT_TYPE(SINT16, signed short, 0x7fff, "%d");
|
||||
DECLARE_FIT_TYPE(SINT32, signed int, 0x7fffffff, "%d");
|
||||
DECLARE_FIT_TYPE(SINT64, signed long long, 0x7fffffffffffffffll, "%lld");
|
||||
|
||||
DECLARE_FIT_TYPE(FLOAT, unsigned int, 0xffffffff);
|
||||
DECLARE_FIT_TYPE(DOUBLE, unsigned long long, 0xffffffffffffffffll);
|
||||
DECLARE_FIT_TYPE(STRING, char *, NULL);
|
||||
DECLARE_FIT_TYPE(FLOAT, unsigned int, 0xffffffff, "%u");
|
||||
DECLARE_FIT_TYPE(DOUBLE, unsigned long long, 0xffffffffffffffffll, "%llu");
|
||||
DECLARE_FIT_TYPE(STRING, char *, NULL, "\"%s\"");
|
||||
|
||||
// Override string value function - it's the pointer itself
|
||||
#define STRING_VALUE(g, p) ((char *)(p))
|
||||
|
||||
static const struct {
|
||||
const char *type_name;
|
||||
@ -447,33 +462,18 @@ struct field_desc {
|
||||
void (*parse)(struct garmin_parser_t *, unsigned char base_type, const unsigned char *data);
|
||||
};
|
||||
|
||||
static inline int base_type_is_integer(unsigned char base_type)
|
||||
{
|
||||
return !memcmp(base_type_info[base_type].type_name + 1, "INT", 3);
|
||||
}
|
||||
|
||||
static inline unsigned long array_uint_endian(const unsigned char *p, unsigned int type_size, unsigned char bigendian)
|
||||
{
|
||||
if (bigendian)
|
||||
return array_uint_be(p, type_size);
|
||||
else
|
||||
return array_uint_le(p, type_size);
|
||||
}
|
||||
|
||||
#define DECLARE_FIELD(msg, name, type) __DECLARE_FIELD(msg##_##name, type)
|
||||
#define __DECLARE_FIELD(name, type) \
|
||||
static void parse_##name(struct garmin_parser_t *, const type); \
|
||||
static void parse_##name##_##type(struct garmin_parser_t *g, unsigned char base_type, const unsigned char *p) \
|
||||
{ \
|
||||
char fmtbuf[FMTSIZE]; \
|
||||
if (strcmp(#type, base_type_info[base_type].type_name)) \
|
||||
fprintf(stderr, "%s: %s should be %s\n", #name, #type, base_type_info[base_type].type_name); \
|
||||
type val; \
|
||||
if (base_type_info[base_type].type_size > 1 && base_type_is_integer(base_type)) \
|
||||
val = (type)array_uint_endian(p, base_type_info[base_type].type_size, g->is_big_endian); \
|
||||
else \
|
||||
val = *(type *)p; \
|
||||
type val = type##_VALUE(g, p); \
|
||||
if (val == type##_INVAL) return; \
|
||||
DEBUG(g->base.context, "%s (%s): %lld", #name, #type, (long long)val); \
|
||||
type##_FORMAT(val, fmtbuf); \
|
||||
DEBUG(g->base.context, "%s (%s): %s", #name, #type, fmtbuf); \
|
||||
parse_##name(g, val); \
|
||||
} \
|
||||
static const struct field_desc name##_field_##type = { #name, parse_##name##_##type }; \
|
||||
@ -484,22 +484,26 @@ static inline unsigned long array_uint_endian(const unsigned char *p, unsigned i
|
||||
// Convert to "standard epoch time" by adding 631065600.
|
||||
DECLARE_FIELD(ANY, timestamp, UINT32)
|
||||
{
|
||||
garmin->record_data.timestamp = data;
|
||||
if (garmin->callback) {
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
// Turn the timestamp relative to the beginning of the dive
|
||||
if (data < garmin->dive.time)
|
||||
if (data < garmin->dive.time) {
|
||||
DEBUG(garmin->base.context, "Timestamp before dive start: %d (dive start: %d)", data, garmin->dive.time);
|
||||
|
||||
return;
|
||||
data -= garmin->dive.time;
|
||||
}
|
||||
data -= garmin->dive.time - 1;
|
||||
|
||||
// Did we already do this?
|
||||
if (data < garmin->record_data.time)
|
||||
if (data == garmin->record_data.time)
|
||||
return;
|
||||
|
||||
garmin->record_data.time = data;
|
||||
|
||||
// Now we're ready to actually update the sample times
|
||||
garmin->record_data.time = data+1;
|
||||
sample.time = data;
|
||||
garmin->callback(DC_SAMPLE_TIME, sample, garmin->userdata);
|
||||
dc_sample_value_t sample = {0};
|
||||
sample.time = data * 1000;
|
||||
garmin->callback(DC_SAMPLE_TIME, &sample, garmin->userdata);
|
||||
}
|
||||
}
|
||||
DECLARE_FIELD(ANY, message_index, UINT16) { garmin->record_data.index = data; }
|
||||
@ -513,6 +517,7 @@ DECLARE_FIELD(FILE, serial, UINT32Z) { }
|
||||
DECLARE_FIELD(FILE, creation_time, UINT32) { }
|
||||
DECLARE_FIELD(FILE, number, UINT16) { }
|
||||
DECLARE_FIELD(FILE, other_time, UINT32) { }
|
||||
DECLARE_FIELD(FILE, product_name, STRING) { }
|
||||
|
||||
// SESSION msg
|
||||
DECLARE_FIELD(SESSION, start_time, UINT32) { garmin->dive.time = data; }
|
||||
@ -545,16 +550,19 @@ DECLARE_FIELD(RECORD, heart_rate, UINT8) // bpm
|
||||
if (garmin->callback) {
|
||||
dc_sample_value_t sample = {0};
|
||||
sample.heartbeat = data;
|
||||
garmin->callback(DC_SAMPLE_HEARTBEAT, sample, garmin->userdata);
|
||||
garmin->callback(DC_SAMPLE_HEARTBEAT, &sample, garmin->userdata);
|
||||
}
|
||||
}
|
||||
DECLARE_FIELD(RECORD, cadence, UINT8) { } // cadence
|
||||
DECLARE_FIELD(RECORD, fract_cadence, UINT8) { } // fractional cadence
|
||||
DECLARE_FIELD(RECORD, distance, UINT32) { } // Distance in 100 * m? WTF?
|
||||
DECLARE_FIELD(RECORD, speed, UINT16) { } // Speed (m/s?)
|
||||
DECLARE_FIELD(RECORD, temperature, SINT8) // degrees C
|
||||
{
|
||||
if (garmin->callback) {
|
||||
dc_sample_value_t sample = {0};
|
||||
sample.temperature = data;
|
||||
garmin->callback(DC_SAMPLE_TEMPERATURE, sample, garmin->userdata);
|
||||
garmin->callback(DC_SAMPLE_TEMPERATURE, &sample, garmin->userdata);
|
||||
}
|
||||
}
|
||||
DECLARE_FIELD(RECORD, abs_pressure, UINT32) {} // Pascal
|
||||
@ -563,7 +571,7 @@ DECLARE_FIELD(RECORD, depth, UINT32) // mm
|
||||
if (garmin->callback) {
|
||||
dc_sample_value_t sample = {0};
|
||||
sample.depth = data / 1000.0;
|
||||
garmin->callback(DC_SAMPLE_DEPTH, sample, garmin->userdata);
|
||||
garmin->callback(DC_SAMPLE_DEPTH, &sample, garmin->userdata);
|
||||
}
|
||||
}
|
||||
DECLARE_FIELD(RECORD, next_stop_depth, UINT32) // mm
|
||||
@ -581,7 +589,7 @@ DECLARE_FIELD(RECORD, tts, UINT32)
|
||||
if (garmin->callback) {
|
||||
dc_sample_value_t sample = {0};
|
||||
sample.time = data;
|
||||
garmin->callback(DC_SAMPLE_TTS, sample, garmin->userdata);
|
||||
garmin->callback(DC_SAMPLE_TTS, &sample, garmin->userdata);
|
||||
}
|
||||
}
|
||||
DECLARE_FIELD(RECORD, ndl, UINT32) // s
|
||||
@ -590,7 +598,7 @@ DECLARE_FIELD(RECORD, ndl, UINT32) // s
|
||||
dc_sample_value_t sample = {0};
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.time = data;
|
||||
garmin->callback(DC_SAMPLE_DECO, sample, garmin->userdata);
|
||||
garmin->callback(DC_SAMPLE_DECO, &sample, garmin->userdata);
|
||||
}
|
||||
}
|
||||
DECLARE_FIELD(RECORD, cns_load, UINT8)
|
||||
@ -598,7 +606,7 @@ DECLARE_FIELD(RECORD, cns_load, UINT8)
|
||||
if (garmin->callback) {
|
||||
dc_sample_value_t sample = {0};
|
||||
sample.cns = data / 100.0;
|
||||
garmin->callback(DC_SAMPLE_CNS, sample, garmin->userdata);
|
||||
garmin->callback(DC_SAMPLE_CNS, &sample, garmin->userdata);
|
||||
}
|
||||
}
|
||||
DECLARE_FIELD(RECORD, n2_load, UINT16) { } // percent
|
||||
@ -635,9 +643,23 @@ DECLARE_FIELD(DEVICE_INFO, firmware, UINT16)
|
||||
garmin->record_data.pending |= RECORD_DEVICE_INFO;
|
||||
}
|
||||
|
||||
// ACTIVITY
|
||||
DECLARE_FIELD(ACTIVITY, total_timer_time, UINT32) { }
|
||||
DECLARE_FIELD(ACTIVITY, num_sessions, UINT16) { }
|
||||
DECLARE_FIELD(ACTIVITY, type, ENUM) { }
|
||||
DECLARE_FIELD(ACTIVITY, event, ENUM) { }
|
||||
DECLARE_FIELD(ACTIVITY, event_type, ENUM) { }
|
||||
DECLARE_FIELD(ACTIVITY, local_timestamp, UINT32)
|
||||
{
|
||||
int time_offset = data - garmin->record_data.timestamp;
|
||||
garmin->dive.time_offset = time_offset;
|
||||
}
|
||||
DECLARE_FIELD(ACTIVITY, event_group, UINT8) { }
|
||||
|
||||
// SPORT
|
||||
DECLARE_FIELD(SPORT, sub_sport, ENUM) {
|
||||
garmin->dive.sub_sport = (ENUM) data;
|
||||
garmin->dive.current_gasmix_usage = DC_USAGE_OPEN_CIRCUIT;
|
||||
dc_divemode_t val;
|
||||
switch (data) {
|
||||
case 55: val = DC_DIVEMODE_GAUGE;
|
||||
@ -645,7 +667,10 @@ DECLARE_FIELD(SPORT, sub_sport, ENUM) {
|
||||
case 56:
|
||||
case 57: val = DC_DIVEMODE_FREEDIVE;
|
||||
break;
|
||||
case 63: val = DC_DIVEMODE_CCR;
|
||||
case 63:
|
||||
val = DC_DIVEMODE_CCR;
|
||||
garmin->dive.current_gasmix_usage = DC_USAGE_DILUENT;
|
||||
|
||||
break;
|
||||
default: val = DC_DIVEMODE_OC;
|
||||
}
|
||||
@ -671,7 +696,10 @@ DECLARE_FIELD(DIVE_GAS, status, ENUM)
|
||||
DECLARE_FIELD(DIVE_GAS, type, ENUM)
|
||||
{
|
||||
// 0 - open circuit, 1 - CCR diluent
|
||||
garmin->record_data.gas_type = data;
|
||||
if (data == 1)
|
||||
garmin->record_data.gasmix.usage = DC_USAGE_DILUENT;
|
||||
else
|
||||
garmin->record_data.gasmix.usage = DC_USAGE_OPEN_CIRCUIT;
|
||||
garmin->record_data.pending |= RECORD_GASMIX;
|
||||
}
|
||||
|
||||
@ -771,12 +799,12 @@ DECLARE_FIELD(SENSOR_PROFILE, ant_channel_id, UINT32Z)
|
||||
{
|
||||
current_sensor(garmin)->sensor_id = data;
|
||||
}
|
||||
DECLARE_FIELD(SENSOR_PROFILE, name, STRING) { } // We don't pass in string types correctly
|
||||
DECLARE_FIELD(SENSOR_PROFILE, name, STRING) { }
|
||||
DECLARE_FIELD(SENSOR_PROFILE, enabled, ENUM)
|
||||
{
|
||||
current_sensor(garmin)->sensor_enabled = data;
|
||||
}
|
||||
DECLARE_FIELD(SENSOR_PROFILE, sensor_type, UINT8)
|
||||
DECLARE_FIELD(SENSOR_PROFILE, sensor_type, ENUM)
|
||||
{
|
||||
// 28 is tank pod
|
||||
// start filling in next sensor after this record
|
||||
@ -848,6 +876,17 @@ DECLARE_FIELD(EVENT, tank_pressure_reserve, UINT32Z) { } // sensor ID
|
||||
DECLARE_FIELD(EVENT, tank_pressure_critical, UINT32Z) { } // sensor ID
|
||||
DECLARE_FIELD(EVENT, tank_pressure_lost, UINT32Z) { } // sensor ID
|
||||
|
||||
// "Field description" (for developer fields)
|
||||
DECLARE_FIELD(FIELD_DESCRIPTION, data_index, UINT8) { }
|
||||
DECLARE_FIELD(FIELD_DESCRIPTION, field_definition, UINT8) { }
|
||||
DECLARE_FIELD(FIELD_DESCRIPTION, base_type, UINT8) { }
|
||||
DECLARE_FIELD(FIELD_DESCRIPTION, name, STRING) { } // "Depth"
|
||||
DECLARE_FIELD(FIELD_DESCRIPTION, scale, UINT8) { }
|
||||
DECLARE_FIELD(FIELD_DESCRIPTION, offset, SINT8) { }
|
||||
DECLARE_FIELD(FIELD_DESCRIPTION, unit, STRING) { } // "feet"
|
||||
DECLARE_FIELD(FIELD_DESCRIPTION, original_mesg, UINT16) { }
|
||||
DECLARE_FIELD(FIELD_DESCRIPTION, original_field, UINT8) { }
|
||||
|
||||
struct msg_desc {
|
||||
unsigned char maxfield;
|
||||
const struct field_desc *field[];
|
||||
@ -860,7 +899,7 @@ struct msg_desc {
|
||||
static const struct msg_desc name##_msg_desc
|
||||
|
||||
DECLARE_MESG(FILE) = {
|
||||
.maxfield = 8,
|
||||
.maxfield = 9,
|
||||
.field = {
|
||||
SET_FIELD(FILE, 0, file_type, ENUM),
|
||||
SET_FIELD(FILE, 1, manufacturer, UINT16),
|
||||
@ -869,6 +908,7 @@ DECLARE_MESG(FILE) = {
|
||||
SET_FIELD(FILE, 4, creation_time, UINT32),
|
||||
SET_FIELD(FILE, 5, number, UINT16),
|
||||
SET_FIELD(FILE, 7, other_time, UINT32),
|
||||
SET_FIELD(FILE, 8, product_name, STRING),
|
||||
}
|
||||
};
|
||||
|
||||
@ -880,6 +920,7 @@ DECLARE_MESG(DEVICE_SETTINGS) = {
|
||||
}
|
||||
};
|
||||
DECLARE_MESG(USER_PROFILE) = { };
|
||||
DECLARE_MESG(HRM_PROFILE) = { };
|
||||
DECLARE_MESG(ZONES_TARGET) = { };
|
||||
|
||||
DECLARE_MESG(SPORT) = {
|
||||
@ -926,8 +967,11 @@ DECLARE_MESG(RECORD) = {
|
||||
SET_FIELD(RECORD, 1, position_long, SINT32), // 180 deg / 2**31
|
||||
SET_FIELD(RECORD, 2, altitude, UINT16), // 5 *m + 500 ?
|
||||
SET_FIELD(RECORD, 3, heart_rate, UINT8), // bpm
|
||||
SET_FIELD(RECORD, 4, cadence, UINT8), // cadence
|
||||
SET_FIELD(RECORD, 5, distance, UINT32), // Distance in 100 * m? WTF?
|
||||
SET_FIELD(RECORD, 6, speed, UINT16), // m/s? Who knows..
|
||||
SET_FIELD(RECORD, 13, temperature, SINT8), // degrees C
|
||||
SET_FIELD(RECORD, 53, fract_cadence, UINT8), // fractional cadence
|
||||
SET_FIELD(RECORD, 91, abs_pressure, UINT32), // Pascal
|
||||
SET_FIELD(RECORD, 92, depth, UINT32), // mm
|
||||
SET_FIELD(RECORD, 93, next_stop_depth, UINT32), // mm
|
||||
@ -998,7 +1042,19 @@ DECLARE_MESG(DEVICE_INFO) = {
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_MESG(ACTIVITY) = { };
|
||||
DECLARE_MESG(ACTIVITY) = {
|
||||
.maxfield = 7,
|
||||
.field = {
|
||||
SET_FIELD(ACTIVITY, 0, total_timer_time, UINT32),
|
||||
SET_FIELD(ACTIVITY, 1, num_sessions, UINT16),
|
||||
SET_FIELD(ACTIVITY, 2, type, ENUM),
|
||||
SET_FIELD(ACTIVITY, 3, event, ENUM),
|
||||
SET_FIELD(ACTIVITY, 4, event_type, ENUM),
|
||||
SET_FIELD(ACTIVITY, 5, local_timestamp, UINT32),
|
||||
SET_FIELD(ACTIVITY, 6, event_group, UINT8),
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_MESG(FILE_CREATOR) = { };
|
||||
|
||||
DECLARE_MESG(DIVE_SETTINGS) = {
|
||||
@ -1041,7 +1097,7 @@ DECLARE_MESG(SENSOR_PROFILE) = {
|
||||
SET_FIELD(SENSOR_PROFILE, 0, ant_channel_id, UINT32Z), // derived from the number engraved on the side
|
||||
SET_FIELD(SENSOR_PROFILE, 2, name, STRING),
|
||||
SET_FIELD(SENSOR_PROFILE, 3, enabled, ENUM),
|
||||
SET_FIELD(SENSOR_PROFILE, 52, sensor_type, UINT8), // 28 is tank pod
|
||||
SET_FIELD(SENSOR_PROFILE, 52, sensor_type, ENUM), // 28 is tank pod
|
||||
SET_FIELD(SENSOR_PROFILE, 74, pressure_units, ENUM), // 0 is PSI, 1 is KPA (unused), 2 is Bar
|
||||
SET_FIELD(SENSOR_PROFILE, 75, rated_pressure, UINT16),
|
||||
SET_FIELD(SENSOR_PROFILE, 76, reserve_pressure, UINT16),
|
||||
@ -1068,6 +1124,22 @@ DECLARE_MESG(TANK_SUMMARY) = {
|
||||
}
|
||||
};
|
||||
|
||||
DECLARE_MESG(FIELD_DESCRIPTION) = {
|
||||
.maxfield = 16,
|
||||
.field = {
|
||||
SET_FIELD(FIELD_DESCRIPTION, 0, data_index, UINT8),
|
||||
SET_FIELD(FIELD_DESCRIPTION, 1, field_definition, UINT8),
|
||||
SET_FIELD(FIELD_DESCRIPTION, 2, base_type, UINT8),
|
||||
SET_FIELD(FIELD_DESCRIPTION, 3, name, STRING), // "Depth"
|
||||
SET_FIELD(FIELD_DESCRIPTION, 6, scale, UINT8),
|
||||
SET_FIELD(FIELD_DESCRIPTION, 7, offset, SINT8),
|
||||
SET_FIELD(FIELD_DESCRIPTION, 8, unit, STRING), // "feet"
|
||||
// Some kind of pointer to original field?
|
||||
SET_FIELD(FIELD_DESCRIPTION, 14, original_mesg, UINT16),
|
||||
SET_FIELD(FIELD_DESCRIPTION, 15, original_field, UINT8),
|
||||
}
|
||||
};
|
||||
|
||||
// Unknown global message ID's..
|
||||
DECLARE_MESG(WTF_13) = { };
|
||||
DECLARE_MESG(WTF_22) = { };
|
||||
@ -1088,6 +1160,7 @@ static const struct {
|
||||
SET_MESG( 0, FILE),
|
||||
SET_MESG( 2, DEVICE_SETTINGS),
|
||||
SET_MESG( 3, USER_PROFILE),
|
||||
SET_MESG( 4, HRM_PROFILE),
|
||||
SET_MESG( 7, ZONES_TARGET),
|
||||
SET_MESG( 12, SPORT),
|
||||
SET_MESG( 13, WTF_13),
|
||||
@ -1108,6 +1181,8 @@ static const struct {
|
||||
|
||||
SET_MESG(147, SENSOR_PROFILE),
|
||||
|
||||
SET_MESG(206, FIELD_DESCRIPTION),
|
||||
|
||||
SET_MESG(216, WTF_216),
|
||||
SET_MESG(233, WTF_233),
|
||||
SET_MESG(258, DIVE_SETTINGS),
|
||||
@ -1142,14 +1217,6 @@ static const struct msg_desc *lookup_msg_desc(unsigned short msg, int local, con
|
||||
return desc;
|
||||
}
|
||||
|
||||
static int traverse_compressed(struct garmin_parser_t *garmin,
|
||||
const unsigned char *data, unsigned int size,
|
||||
unsigned char type, unsigned int time)
|
||||
{
|
||||
fprintf(stderr, "Compressed record for local type %d:\n", type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int all_data_inval(const unsigned char *data, int base_type, int len)
|
||||
{
|
||||
int base_size = base_type_info[base_type].type_size;
|
||||
@ -1241,20 +1308,17 @@ static int traverse_regular(struct garmin_parser_t *garmin,
|
||||
|
||||
if (!len) {
|
||||
ERROR(garmin->base.context, "field with zero length\n");
|
||||
return -1;
|
||||
return total_len + size;
|
||||
}
|
||||
|
||||
if (size < len) {
|
||||
ERROR(garmin->base.context, "Data traversal size bigger than remaining data (%d vs %d)\n", len, size);
|
||||
return -1;
|
||||
return total_len + size;
|
||||
}
|
||||
|
||||
if (base_type > 16) {
|
||||
ERROR(garmin->base.context, "Unknown base type %d\n", base_type);
|
||||
data += size;
|
||||
len -= size;
|
||||
total_len += size;
|
||||
continue;
|
||||
return total_len + size;
|
||||
}
|
||||
base_size = base_type_info[base_type].type_size;
|
||||
if (len % base_size) {
|
||||
@ -1280,7 +1344,10 @@ static int traverse_regular(struct garmin_parser_t *garmin,
|
||||
}
|
||||
|
||||
if (field_desc) {
|
||||
field_desc->parse(garmin, base_type, data);
|
||||
if (field_nr == 253 && !msg_desc->maxfield)
|
||||
DEBUG(garmin->base.context, "Ignoring timestamp field for undefined message.");
|
||||
else
|
||||
field_desc->parse(garmin, base_type, data);
|
||||
} else {
|
||||
unknown_field(garmin, data, msg_name, field_nr, base_type, len);
|
||||
}
|
||||
@ -1290,6 +1357,31 @@ static int traverse_regular(struct garmin_parser_t *garmin,
|
||||
size -= len;
|
||||
}
|
||||
|
||||
for (int i = 0; i < desc->devfields; i++) {
|
||||
int desc_idx = i + desc->nrfields;
|
||||
const unsigned char *field = desc->fields[desc_idx];
|
||||
unsigned int field_nr = field[0];
|
||||
unsigned int len = field[1];
|
||||
unsigned int type = field[2];
|
||||
|
||||
DEBUG(garmin->base.context, "Developer field %d %02x type %02x", i, field_nr, type);
|
||||
|
||||
if (!len) {
|
||||
ERROR(garmin->base.context, " developer field with zero length\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (size < len) {
|
||||
ERROR(garmin->base.context, " developer field bigger than remaining data (%d vs %d)\n", len, size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
HEXDUMP(garmin->base.context, DC_LOGLEVEL_DEBUG, "data", data, len);
|
||||
data += len;
|
||||
total_len += len;
|
||||
size -= len;
|
||||
}
|
||||
|
||||
return total_len;
|
||||
}
|
||||
|
||||
@ -1325,7 +1417,7 @@ static int traverse_definition(struct garmin_parser_t *garmin,
|
||||
|
||||
// data[1] tells us if this is big or little endian
|
||||
garmin->is_big_endian = data[1] != 0;
|
||||
msg = array_uint_endian(data + 2, 2, garmin->is_big_endian);
|
||||
msg = garmin_value(garmin, data + 2, 2);
|
||||
desc->msg_desc = lookup_msg_desc(msg, type, &desc->msg_name);
|
||||
fields = data[4];
|
||||
DEBUG(garmin->base.context, "Define local type %d: %02x %s %04x %02x %s",
|
||||
@ -1337,12 +1429,6 @@ static int traverse_definition(struct garmin_parser_t *garmin,
|
||||
desc->nrfields = fields;
|
||||
len = 5 + fields*3;
|
||||
devfields = 0;
|
||||
if (record & 0x20) {
|
||||
devfields = data[len];
|
||||
len += 1 + devfields*3;
|
||||
ERROR(garmin->base.context, "NO support for developer fields yet\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < fields; i++) {
|
||||
unsigned char *field = desc->fields[i];
|
||||
@ -1350,6 +1436,34 @@ static int traverse_definition(struct garmin_parser_t *garmin,
|
||||
DEBUG(garmin->base.context, " %d: %02x %02x %02x", i, field[0], field[1], field[2]);
|
||||
}
|
||||
|
||||
data += len;
|
||||
|
||||
/* Developer fields after the regular ones */
|
||||
if (record & 0x20) {
|
||||
devfields = data[0];
|
||||
DEBUG(garmin->base.context, "Developer field (rec=%02x len=%d, devfields=%d)",
|
||||
record, len, devfields);
|
||||
|
||||
/*
|
||||
* one byte of dev field numbers, each three bytes in size
|
||||
* (number/size/index)
|
||||
*/
|
||||
len += 1 + 3*devfields;
|
||||
|
||||
for (int i = 0; i < devfields; i++) {
|
||||
int idx = fields + i;
|
||||
unsigned char *field = desc->fields[idx];
|
||||
if (idx > MAXFIELDS) {
|
||||
ERROR(garmin->base.context, "Too many dev fields in description: %d+%d (max %d)\n", fields, i, MAXFIELDS);
|
||||
return -1;
|
||||
}
|
||||
memcpy(field, data + (1+i*3), 3);
|
||||
DEBUG(garmin->base.context, " %d: %02x %02x %02x", i, field[0], field[1], field[2]);
|
||||
}
|
||||
}
|
||||
|
||||
desc->devfields = devfields;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -1370,7 +1484,7 @@ traverse_data(struct garmin_parser_t *garmin)
|
||||
if (len < FIT_NAME_SIZE)
|
||||
return DC_STATUS_IO;
|
||||
|
||||
DEBUG(garmin->base.context, "file %s", data);
|
||||
DEBUG(garmin->base.context, "file %.*s", FIT_NAME_SIZE, data);
|
||||
|
||||
data += FIT_NAME_SIZE;
|
||||
len -= FIT_NAME_SIZE;
|
||||
@ -1414,10 +1528,20 @@ traverse_data(struct garmin_parser_t *garmin)
|
||||
newtime += 0x20;
|
||||
time = newtime;
|
||||
|
||||
len = traverse_compressed(garmin, data, datasize, type, time);
|
||||
// Compressed records are like normal records
|
||||
// with that added relative timestamp
|
||||
DEBUG(garmin->base.context, "Compressed record for type %d", type);
|
||||
|
||||
if (!(garmin->type_desc + type)->msg_desc->maxfield)
|
||||
DEBUG(garmin->base.context, "Ignoring timestamp field for undefined message.");
|
||||
else
|
||||
parse_ANY_timestamp(garmin, time);
|
||||
|
||||
len = traverse_regular(garmin, data, datasize, type, &time);
|
||||
} else if (record & 0x40) { // Definition record?
|
||||
len = traverse_definition(garmin, data, datasize, record);
|
||||
} else { // Normal data record
|
||||
DEBUG(garmin->base.context, "Regular record for type %d", record);
|
||||
len = traverse_regular(garmin, data, datasize, record, &time);
|
||||
}
|
||||
if (len <= 0 || len > datasize)
|
||||
@ -1471,10 +1595,8 @@ static void add_gps_string(garmin_parser_t *garmin, const char *desc, struct pos
|
||||
}
|
||||
|
||||
int
|
||||
garmin_parser_is_dive (dc_parser_t *abstract, const unsigned char *data, unsigned int size, dc_event_devinfo_t *devinfo_p)
|
||||
garmin_parser_is_dive (dc_parser_t *abstract, dc_event_devinfo_t *devinfo_p)
|
||||
{
|
||||
// set up the parser and extract data
|
||||
dc_parser_set_data(abstract, data, size);
|
||||
garmin_parser_t *garmin = (garmin_parser_t *) abstract;
|
||||
|
||||
if (devinfo_p) {
|
||||
@ -1506,9 +1628,21 @@ static void add_sensor_string(garmin_parser_t *garmin, const char *desc, const s
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
garmin_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
garmin_parser_set_data (garmin_parser_t *garmin, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
garmin_parser_t *garmin = (garmin_parser_t *) abstract;
|
||||
// This list is empirical and somewhat speculative
|
||||
// will have to be confirmed with Garmin
|
||||
static const struct {
|
||||
int id;
|
||||
const char *name;
|
||||
} models[] = {
|
||||
{ 2859, "Descent Mk1" },
|
||||
{ 2991, "Descent Mk1 APAC" },
|
||||
{ 3258, "Descent Mk2(i)" },
|
||||
{ 3542, "Descent Mk2s" },
|
||||
{ 3702, "Descent Mk2 APAC" },
|
||||
{ 4223, "Descent Mk3" },
|
||||
};
|
||||
|
||||
/* Walk the data once without a callback to set up the core fields */
|
||||
garmin->callback = NULL;
|
||||
@ -1520,9 +1654,22 @@ garmin_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsign
|
||||
traverse_data(garmin);
|
||||
|
||||
// Device information
|
||||
dc_field_add_string_fmt(&garmin->cache, "Serial", "%u", garmin->dive.serial);
|
||||
dc_field_add_string_fmt(&garmin->cache, "Firmware", "%u.%02u",
|
||||
garmin->dive.firmware / 100, garmin->dive.firmware % 100);
|
||||
if (garmin->dive.serial)
|
||||
dc_field_add_string_fmt(&garmin->cache, "Serial", "%u", garmin->dive.serial);
|
||||
if (garmin->dive.firmware)
|
||||
dc_field_add_string_fmt(&garmin->cache, "Firmware", "%u.%02u",
|
||||
garmin->dive.firmware / 100, garmin->dive.firmware % 100);
|
||||
if (garmin->dive.product) {
|
||||
int i = 0;
|
||||
for (i = 0; i < C_ARRAY_SIZE(models); i++)
|
||||
if (models[i].id == garmin->dive.product)
|
||||
break;
|
||||
|
||||
if (i < C_ARRAY_SIZE(models))
|
||||
dc_field_add_string_fmt(&garmin->cache, "Model", "%s", models[i].name);
|
||||
else
|
||||
dc_field_add_string_fmt(&garmin->cache, "Model", "Unknown model ID: %u", garmin->dive.product);
|
||||
}
|
||||
|
||||
// These seem to be the "real" GPS dive coordinates
|
||||
add_gps_string(garmin, "GPS1", &garmin->gps.SESSION.entry);
|
||||
@ -1549,10 +1696,8 @@ garmin_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsign
|
||||
//
|
||||
// There's no way to match them up unless they are an identity
|
||||
// mapping, so having two different ones doesn't actually work.
|
||||
if (garmin->dive.nr_sensor > garmin->cache.GASMIX_COUNT) {
|
||||
DC_ASSIGN_FIELD(garmin->cache, GASMIX_COUNT, garmin->dive.nr_sensor);
|
||||
garmin->cache.initialized |= 1 << DC_FIELD_TANK_COUNT;
|
||||
}
|
||||
if (garmin->dive.nr_sensor > garmin->cache.TANK_COUNT)
|
||||
DC_ASSIGN_FIELD(garmin->cache, TANK_COUNT, garmin->dive.nr_sensor);
|
||||
|
||||
for (int i = 0; i < garmin->dive.nr_sensor; i++) {
|
||||
static const char *name[] = { "Sensor 1", "Sensor 2", "Sensor 3", "Sensor 4", "Sensor 5" };
|
||||
@ -1586,10 +1731,22 @@ garmin_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
garmin_parser_t *garmin = (garmin_parser_t *) abstract;
|
||||
dc_ticks_t time = 631065600 + (dc_ticks_t) garmin->dive.time;
|
||||
int timezone = DC_TIMEZONE_NONE;
|
||||
|
||||
// Show local time (time_offset)
|
||||
dc_datetime_gmtime(datetime, time + garmin->dive.time_offset);
|
||||
datetime->timezone = DC_TIMEZONE_NONE;
|
||||
|
||||
/* See if we might have a valid timezone offset */
|
||||
if (garmin->dive.time_offset || garmin->dive.utc_offset) {
|
||||
int offset = garmin->dive.time_offset - garmin->dive.utc_offset;
|
||||
|
||||
/* 15-minute (900-second) offsets are real */
|
||||
if ((offset % 900) == 0 &&
|
||||
offset >= -12*60*60 &&
|
||||
offset <= 14*60*60)
|
||||
timezone = offset;
|
||||
}
|
||||
datetime->timezone = timezone;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
406
src/hdlc.c
Normal file
406
src/hdlc.c
Normal file
@ -0,0 +1,406 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2023 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> // malloc, free
|
||||
|
||||
#include "hdlc.h"
|
||||
|
||||
#include "iostream-private.h"
|
||||
#include "common-private.h"
|
||||
#include "context-private.h"
|
||||
|
||||
#define END 0x7E
|
||||
#define ESC 0x7D
|
||||
#define ESC_BIT 0x20
|
||||
|
||||
static dc_status_t dc_hdlc_set_timeout (dc_iostream_t *abstract, int timeout);
|
||||
static dc_status_t dc_hdlc_set_break (dc_iostream_t *abstract, unsigned int value);
|
||||
static dc_status_t dc_hdlc_set_dtr (dc_iostream_t *abstract, unsigned int value);
|
||||
static dc_status_t dc_hdlc_set_rts (dc_iostream_t *abstract, unsigned int value);
|
||||
static dc_status_t dc_hdlc_get_lines (dc_iostream_t *abstract, unsigned int *value);
|
||||
static dc_status_t dc_hdlc_configure (dc_iostream_t *abstract, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol);
|
||||
static dc_status_t dc_hdlc_poll (dc_iostream_t *abstract, int timeout);
|
||||
static dc_status_t dc_hdlc_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual);
|
||||
static dc_status_t dc_hdlc_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual);
|
||||
static dc_status_t dc_hdlc_ioctl (dc_iostream_t *abstract, unsigned int request, void *data, size_t size);
|
||||
static dc_status_t dc_hdlc_flush (dc_iostream_t *abstract);
|
||||
static dc_status_t dc_hdlc_purge (dc_iostream_t *abstract, dc_direction_t direction);
|
||||
static dc_status_t dc_hdlc_sleep (dc_iostream_t *abstract, unsigned int milliseconds);
|
||||
static dc_status_t dc_hdlc_close (dc_iostream_t *abstract);
|
||||
|
||||
typedef struct dc_hdlc_t {
|
||||
/* Base class. */
|
||||
dc_iostream_t base;
|
||||
/* Internal state. */
|
||||
dc_context_t *context;
|
||||
dc_iostream_t *iostream;
|
||||
unsigned char *rbuf;
|
||||
unsigned char *wbuf;
|
||||
size_t rbuf_size;
|
||||
size_t rbuf_offset;
|
||||
size_t rbuf_available;
|
||||
size_t wbuf_size;
|
||||
size_t wbuf_offset;
|
||||
} dc_hdlc_t;
|
||||
|
||||
static const dc_iostream_vtable_t dc_hdlc_vtable = {
|
||||
sizeof(dc_hdlc_t),
|
||||
dc_hdlc_set_timeout, /* set_timeout */
|
||||
dc_hdlc_set_break, /* set_break */
|
||||
dc_hdlc_set_dtr, /* set_dtr */
|
||||
dc_hdlc_set_rts, /* set_rts */
|
||||
dc_hdlc_get_lines, /* get_lines */
|
||||
NULL, /* get_available */
|
||||
dc_hdlc_configure, /* configure */
|
||||
dc_hdlc_poll, /* poll */
|
||||
dc_hdlc_read, /* read */
|
||||
dc_hdlc_write, /* write */
|
||||
dc_hdlc_ioctl, /* ioctl */
|
||||
dc_hdlc_flush, /* flush */
|
||||
dc_hdlc_purge, /* purge */
|
||||
dc_hdlc_sleep, /* sleep */
|
||||
dc_hdlc_close, /* close */
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
dc_hdlc_open (dc_iostream_t **out, dc_context_t *context, dc_iostream_t *base, size_t isize, size_t osize)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_hdlc_t *hdlc = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (base == NULL || isize == 0 || osize == 0)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
dc_transport_t transport = dc_iostream_get_transport (base);
|
||||
|
||||
// Allocate memory.
|
||||
hdlc = (dc_hdlc_t *) dc_iostream_allocate (NULL, &dc_hdlc_vtable, transport);
|
||||
if (hdlc == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// Allocate the read buffer.
|
||||
hdlc->rbuf = malloc (isize);
|
||||
if (hdlc->rbuf == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Allocate the write buffer.
|
||||
hdlc->wbuf = malloc (osize);
|
||||
if (hdlc->wbuf == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free_rbuf;
|
||||
}
|
||||
|
||||
hdlc->context = context;
|
||||
hdlc->iostream = base;
|
||||
hdlc->rbuf_size = isize;
|
||||
hdlc->rbuf_offset = 0;
|
||||
hdlc->rbuf_available = 0;
|
||||
hdlc->wbuf_size = osize;
|
||||
hdlc->wbuf_offset = 0;
|
||||
|
||||
*out = (dc_iostream_t *) hdlc;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free_rbuf:
|
||||
free (hdlc->rbuf);
|
||||
error_free:
|
||||
dc_iostream_deallocate ((dc_iostream_t *) hdlc);
|
||||
error_exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_hdlc_set_timeout (dc_iostream_t *abstract, int timeout)
|
||||
{
|
||||
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||
|
||||
return dc_iostream_set_timeout (hdlc->iostream, timeout);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_hdlc_set_break (dc_iostream_t *abstract, unsigned int value)
|
||||
{
|
||||
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||
|
||||
return dc_iostream_set_break (hdlc->iostream, value);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_hdlc_set_dtr (dc_iostream_t *abstract, unsigned int value)
|
||||
{
|
||||
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||
|
||||
return dc_iostream_set_dtr (hdlc->iostream, value);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_hdlc_set_rts (dc_iostream_t *abstract, unsigned int value)
|
||||
{
|
||||
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||
|
||||
return dc_iostream_set_rts (hdlc->iostream, value);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_hdlc_get_lines (dc_iostream_t *abstract, unsigned int *value)
|
||||
{
|
||||
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||
|
||||
return dc_iostream_get_lines (hdlc->iostream, value);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_hdlc_configure (dc_iostream_t *abstract, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol)
|
||||
{
|
||||
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||
|
||||
return dc_iostream_configure (hdlc->iostream, baudrate, databits, parity, stopbits, flowcontrol);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_hdlc_poll (dc_iostream_t *abstract, int timeout)
|
||||
{
|
||||
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||
|
||||
if (hdlc->rbuf_available) {
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return dc_iostream_poll (hdlc->iostream, timeout);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_hdlc_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||
size_t nbytes = 0;
|
||||
|
||||
unsigned int initialized = 0;
|
||||
unsigned int escaped = 0;
|
||||
|
||||
while (1) {
|
||||
if (hdlc->rbuf_available == 0) {
|
||||
// Read a packet into the cache.
|
||||
size_t len = 0;
|
||||
status = dc_iostream_read (hdlc->iostream, hdlc->rbuf, hdlc->rbuf_size, &len);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
hdlc->rbuf_available = len;
|
||||
hdlc->rbuf_offset = 0;
|
||||
}
|
||||
|
||||
while (hdlc->rbuf_available) {
|
||||
unsigned char c = hdlc->rbuf[hdlc->rbuf_offset];
|
||||
hdlc->rbuf_offset++;
|
||||
hdlc->rbuf_available--;
|
||||
|
||||
if (c == END) {
|
||||
if (escaped) {
|
||||
ERROR (hdlc->context, "HDLC frame escaped the special character %02x.", c);
|
||||
status = DC_STATUS_IO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (initialized) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
initialized = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!initialized) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == ESC) {
|
||||
if (escaped) {
|
||||
ERROR (hdlc->context, "HDLC frame escaped the special character %02x.", c);
|
||||
status = DC_STATUS_IO;
|
||||
goto out;
|
||||
}
|
||||
escaped = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (escaped) {
|
||||
c ^= ESC_BIT;
|
||||
escaped = 0;
|
||||
}
|
||||
|
||||
if (nbytes < size)
|
||||
((unsigned char *)data)[nbytes] = c;
|
||||
nbytes++;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (nbytes > size) {
|
||||
ERROR (hdlc->context, "HDLC frame is too large (" DC_PRINTF_SIZE " " DC_PRINTF_SIZE ").", nbytes, size);
|
||||
dc_status_set_error (&status, DC_STATUS_IO);
|
||||
nbytes = size;
|
||||
}
|
||||
|
||||
if (actual)
|
||||
*actual = nbytes;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_hdlc_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||
size_t nbytes = 0;
|
||||
|
||||
// Clear the buffer.
|
||||
hdlc->wbuf_offset = 0;
|
||||
|
||||
// Start of the packet.
|
||||
hdlc->wbuf[hdlc->wbuf_offset++] = END;
|
||||
|
||||
// Flush the buffer if necessary.
|
||||
if (hdlc->wbuf_offset >= hdlc->wbuf_size) {
|
||||
status = dc_iostream_write (hdlc->iostream, hdlc->wbuf, hdlc->wbuf_offset, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
hdlc->wbuf_offset = 0;
|
||||
}
|
||||
|
||||
while (nbytes < size) {
|
||||
unsigned char c = ((const unsigned char *) data)[nbytes];
|
||||
|
||||
if (c == END || c == ESC) {
|
||||
// Append the escape character.
|
||||
hdlc->wbuf[hdlc->wbuf_offset++] = ESC;
|
||||
|
||||
// Flush the buffer if necessary.
|
||||
if (hdlc->wbuf_offset >= hdlc->wbuf_size) {
|
||||
status = dc_iostream_write (hdlc->iostream, hdlc->wbuf, hdlc->wbuf_offset, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
hdlc->wbuf_offset = 0;
|
||||
}
|
||||
|
||||
// Escape the character.
|
||||
c ^= ESC_BIT;
|
||||
}
|
||||
|
||||
// Append the character.
|
||||
hdlc->wbuf[hdlc->wbuf_offset++] = c;
|
||||
|
||||
// Flush the buffer if necessary.
|
||||
if (hdlc->wbuf_offset >= hdlc->wbuf_size) {
|
||||
status = dc_iostream_write (hdlc->iostream, hdlc->wbuf, hdlc->wbuf_offset, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
hdlc->wbuf_offset = 0;
|
||||
}
|
||||
|
||||
nbytes++;
|
||||
}
|
||||
|
||||
// End of the packet.
|
||||
hdlc->wbuf[hdlc->wbuf_offset++] = END;
|
||||
|
||||
// Flush the buffer.
|
||||
status = dc_iostream_write (hdlc->iostream, hdlc->wbuf, hdlc->wbuf_offset, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
hdlc->wbuf_offset = 0;
|
||||
|
||||
out:
|
||||
if (actual)
|
||||
*actual = nbytes;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_hdlc_ioctl (dc_iostream_t *abstract, unsigned int request, void *data, size_t size)
|
||||
{
|
||||
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||
|
||||
return dc_iostream_ioctl (hdlc->iostream, request, data, size);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_hdlc_flush (dc_iostream_t *abstract)
|
||||
{
|
||||
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||
|
||||
return dc_iostream_flush (hdlc->iostream);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_hdlc_purge (dc_iostream_t *abstract, dc_direction_t direction)
|
||||
{
|
||||
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||
|
||||
if (direction & DC_DIRECTION_INPUT) {
|
||||
hdlc->rbuf_available = 0;
|
||||
hdlc->rbuf_offset = 0;
|
||||
}
|
||||
|
||||
return dc_iostream_purge (hdlc->iostream, direction);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_hdlc_sleep (dc_iostream_t *abstract, unsigned int milliseconds)
|
||||
{
|
||||
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||
|
||||
return dc_iostream_sleep (hdlc->iostream, milliseconds);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_hdlc_close (dc_iostream_t *abstract)
|
||||
{
|
||||
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||
|
||||
free (hdlc->wbuf);
|
||||
free (hdlc->rbuf);
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
50
src/hdlc.h
Normal file
50
src/hdlc.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2023 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 DC_HDLC_H
|
||||
#define DC_HDLC_H
|
||||
|
||||
#include <libdivecomputer/common.h>
|
||||
#include <libdivecomputer/context.h>
|
||||
#include <libdivecomputer/iostream.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* Create a HDLC I/O stream layered on top of another base I/O stream.
|
||||
*
|
||||
* @param[out] iostream A location to store the HDLC I/O stream.
|
||||
* @param[in] context A valid context.
|
||||
* @param[in] base A valid I/O stream.
|
||||
* @param[in] isize The input packet size in bytes.
|
||||
* @param[in] osize The output packet size in bytes.
|
||||
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
|
||||
* on failure.
|
||||
*/
|
||||
dc_status_t
|
||||
dc_hdlc_open (dc_iostream_t **iostream, dc_context_t *context, dc_iostream_t *base, size_t isize, size_t osize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* DC_HDLC_H */
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
hw_ostc_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial);
|
||||
hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int serial);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
#include "array.h"
|
||||
#include "aes.h"
|
||||
#include "platform.h"
|
||||
#include "packet.h"
|
||||
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc3_device_vtable)
|
||||
|
||||
@ -119,9 +120,6 @@ typedef struct hw_ostc3_device_t {
|
||||
unsigned int firmware;
|
||||
unsigned char fingerprint[5];
|
||||
hw_ostc3_state_t state;
|
||||
unsigned char cache[244];
|
||||
unsigned int available;
|
||||
unsigned int offset;
|
||||
} hw_ostc3_device_t;
|
||||
|
||||
typedef struct hw_ostc3_logbook_t {
|
||||
@ -207,41 +205,20 @@ static dc_status_t
|
||||
hw_ostc3_read (hw_ostc3_device_t *device, dc_event_progress_t *progress, unsigned char data[], size_t size)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
|
||||
|
||||
size_t nbytes = 0;
|
||||
while (nbytes < size) {
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
if (device->available == 0) {
|
||||
// Read a packet into the cache.
|
||||
size_t len = 0;
|
||||
rc = dc_iostream_read (device->iostream, device->cache, sizeof(device->cache), &len);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
device->available = len;
|
||||
device->offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the minimum packet size.
|
||||
size_t length = (transport == DC_TRANSPORT_BLE) ? device->available : 1024;
|
||||
size_t length = 1024;
|
||||
|
||||
// Limit the packet size to the total size.
|
||||
if (nbytes + length > size)
|
||||
length = size - nbytes;
|
||||
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
// Copy the data from the cached packet.
|
||||
memcpy (data + nbytes, device->cache + device->offset, length);
|
||||
device->available -= length;
|
||||
device->offset += length;
|
||||
} else {
|
||||
// Read the packet.
|
||||
rc = dc_iostream_read (device->iostream, data + nbytes, length, NULL);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
}
|
||||
// Read the packet.
|
||||
rc = dc_iostream_read (device->iostream, data + nbytes, length, NULL);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
// Update and emit a progress event.
|
||||
if (progress) {
|
||||
@ -259,12 +236,11 @@ static dc_status_t
|
||||
hw_ostc3_write (hw_ostc3_device_t *device, dc_event_progress_t *progress, const unsigned char data[], size_t size)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
|
||||
|
||||
size_t nbytes = 0;
|
||||
while (nbytes < size) {
|
||||
// Set the maximum packet size.
|
||||
size_t length = (transport == DC_TRANSPORT_BLE) ? sizeof(device->cache) : 64;
|
||||
size_t length = (device->hardware == OSTC4) ? 64 : 1024;
|
||||
|
||||
// Limit the packet size to the total size.
|
||||
if (nbytes + length > size)
|
||||
@ -313,7 +289,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
|
||||
|
||||
// Send the command.
|
||||
unsigned char command[1] = {cmd};
|
||||
status = hw_ostc3_write (device, NULL, command, sizeof (command));
|
||||
status = dc_iostream_write (device->iostream, command, sizeof (command), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return status;
|
||||
@ -321,7 +297,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
|
||||
|
||||
// Read the echo.
|
||||
unsigned char echo[1] = {0};
|
||||
status = hw_ostc3_read (device, NULL, echo, sizeof (echo));
|
||||
status = dc_iostream_read (device->iostream, echo, sizeof (echo), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the echo.");
|
||||
return status;
|
||||
@ -407,14 +383,14 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
|
||||
}
|
||||
}
|
||||
|
||||
if (delay && device->available == 0) {
|
||||
if (delay) {
|
||||
dc_iostream_poll (device->iostream, delay);
|
||||
}
|
||||
|
||||
if (cmd != EXIT) {
|
||||
// Read the ready byte.
|
||||
unsigned char answer[1] = {0};
|
||||
status = hw_ostc3_read (device, NULL, answer, sizeof (answer));
|
||||
status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the ready byte.");
|
||||
return status;
|
||||
@ -439,6 +415,7 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *i
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
hw_ostc3_device_t *device = NULL;
|
||||
dc_transport_t transport = dc_iostream_get_transport (iostream);
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
@ -451,29 +428,36 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *i
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
device->iostream = iostream;
|
||||
device->hardware = INVALID;
|
||||
device->feature = 0;
|
||||
device->model = 0;
|
||||
device->serial = 0;
|
||||
device->firmware = 0;
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
memset (device->cache, 0, sizeof (device->cache));
|
||||
device->available = 0;
|
||||
device->offset = 0;
|
||||
|
||||
// Create the packet stream.
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
status = dc_packet_open (&device->iostream, context, iostream, 244, 20);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to create the packet stream.");
|
||||
goto error_free;
|
||||
}
|
||||
} else {
|
||||
device->iostream = iostream;
|
||||
}
|
||||
|
||||
// Set the serial communication protocol (115200 8N1).
|
||||
status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the terminal attributes.");
|
||||
goto error_free;
|
||||
goto error_free_iostream;
|
||||
}
|
||||
|
||||
// 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;
|
||||
goto error_free_iostream;
|
||||
}
|
||||
|
||||
// Make sure everything is in a sane state.
|
||||
@ -486,6 +470,10 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *i
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free_iostream:
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
dc_iostream_close (device->iostream);
|
||||
}
|
||||
error_free:
|
||||
dc_device_deallocate ((dc_device_t *) device);
|
||||
return status;
|
||||
@ -548,14 +536,14 @@ hw_ostc3_device_init_service (hw_ostc3_device_t *device)
|
||||
unsigned char answer[5] = {0};
|
||||
|
||||
// Send the command and service key.
|
||||
status = hw_ostc3_write (device, NULL, command, sizeof (command));
|
||||
status = dc_iostream_write (device->iostream, command, sizeof (command), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Read the response.
|
||||
status = hw_ostc3_read (device, NULL, answer, sizeof (answer));
|
||||
status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the answer.");
|
||||
return status;
|
||||
@ -656,6 +644,15 @@ hw_ostc3_device_close (dc_device_t *abstract)
|
||||
}
|
||||
}
|
||||
|
||||
// Close the packet stream.
|
||||
if (dc_iostream_get_transport (device->iostream) == DC_TRANSPORT_BLE) {
|
||||
rc = dc_iostream_close (device->iostream);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to close the packet stream.");
|
||||
dc_status_set_error(&status, rc);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -1506,7 +1503,7 @@ hw_ostc3_device_fwupdate3 (dc_device_t *abstract, const char *filename)
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc3_device_fwupdate4 (dc_device_t *abstract, const char *filename)
|
||||
hw_ostc3_device_fwupdate4 (dc_device_t *abstract, const char *filename, bool forceUpdate)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract;
|
||||
@ -1577,7 +1574,7 @@ hw_ostc3_device_fwupdate4 (dc_device_t *abstract, const char *filename)
|
||||
// Upload the firmware blob.
|
||||
// The update is skipped if the two versions are already
|
||||
// identical, or if the blob is not present on the device.
|
||||
if (memcmp(data + offset + 12, fwinfo, sizeof(fwinfo)) != 0 &&
|
||||
if ((memcmp(data + offset + 12, fwinfo, sizeof(fwinfo)) != 0 || forceUpdate) &&
|
||||
!array_isequal(fwinfo, sizeof(fwinfo), 0xFF))
|
||||
{
|
||||
status = hw_ostc3_transfer (device, &progress, S_UPLOAD,
|
||||
@ -1600,7 +1597,7 @@ error:
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
hw_ostc3_device_fwupdate (dc_device_t *abstract, const char *filename)
|
||||
hw_ostc3_device_fwupdate (dc_device_t *abstract, const char *filename, bool forceUpdate)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract;
|
||||
@ -1615,8 +1612,12 @@ hw_ostc3_device_fwupdate (dc_device_t *abstract, const char *filename)
|
||||
}
|
||||
|
||||
if (device->hardware == OSTC4) {
|
||||
return hw_ostc3_device_fwupdate4 (abstract, filename);
|
||||
return hw_ostc3_device_fwupdate4 (abstract, filename, forceUpdate);
|
||||
} else {
|
||||
if (forceUpdate) {
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
return hw_ostc3_device_fwupdate3 (abstract, filename);
|
||||
}
|
||||
}
|
||||
@ -1718,6 +1719,10 @@ hw_ostc3_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (device->hardware == OSTC4) {
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.firmware = device->firmware;
|
||||
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
hw_ostc3_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int model);
|
||||
hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model, unsigned int serial);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -39,13 +39,10 @@
|
||||
|
||||
#define MAXCONFIG 7
|
||||
#define NGASMIXES 15
|
||||
#define OSTC4_CC_DILUENT_GAS_OFFSET 5
|
||||
|
||||
#define UNDEFINED 0xFFFFFFFF
|
||||
|
||||
#define ALL 0
|
||||
#define FIXED 1
|
||||
#define MANUAL 2
|
||||
|
||||
#define HEADER 1
|
||||
#define PROFILE 2
|
||||
|
||||
@ -116,10 +113,12 @@ typedef struct hw_ostc_layout_t {
|
||||
} hw_ostc_layout_t;
|
||||
|
||||
typedef struct hw_ostc_gasmix_t {
|
||||
unsigned int id;
|
||||
unsigned int oxygen;
|
||||
unsigned int helium;
|
||||
unsigned int type;
|
||||
unsigned int enabled;
|
||||
unsigned int active;
|
||||
unsigned int diluent;
|
||||
} hw_ostc_gasmix_t;
|
||||
|
||||
@ -135,21 +134,23 @@ typedef struct hw_ostc_parser_t {
|
||||
const hw_ostc_layout_t *layout;
|
||||
unsigned int ngasmixes;
|
||||
unsigned int nfixed;
|
||||
unsigned int ndisabled;
|
||||
unsigned int initial;
|
||||
unsigned int initial_setpoint;
|
||||
unsigned int initial_cns;
|
||||
hw_ostc_gasmix_t gasmix[NGASMIXES];
|
||||
unsigned int current_divemode_ccr;
|
||||
} hw_ostc_parser_t;
|
||||
|
||||
static dc_status_t hw_ostc_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
|
||||
static dc_status_t hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t callback, void *userdata);
|
||||
|
||||
static const dc_parser_vtable_t hw_ostc_parser_vtable = {
|
||||
sizeof(hw_ostc_parser_t),
|
||||
DC_FAMILY_HW_OSTC,
|
||||
hw_ostc_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -214,15 +215,10 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc3 = {
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
hw_ostc_find_gasmix (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he, unsigned int dil, unsigned int type)
|
||||
hw_ostc_find_gasmix_manual (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he, unsigned int dil)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
unsigned int offset = parser->nfixed - parser->ndisabled;
|
||||
unsigned int count = parser->ngasmixes;
|
||||
if (type == FIXED) {
|
||||
count = parser->nfixed;
|
||||
} else if (type == MANUAL) {
|
||||
offset = parser->nfixed;
|
||||
}
|
||||
|
||||
unsigned int i = offset;
|
||||
while (i < count) {
|
||||
@ -234,6 +230,22 @@ hw_ostc_find_gasmix (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he,
|
||||
return i;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
hw_ostc_find_gasmix_fixed (hw_ostc_parser_t *parser, unsigned int id)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
unsigned int count = parser->nfixed - parser->ndisabled;
|
||||
|
||||
unsigned int i = offset;
|
||||
while (i < count) {
|
||||
if (id == parser->gasmix[i].id)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
hw_ostc_is_ccr (unsigned int divemode, unsigned int version)
|
||||
{
|
||||
@ -315,19 +327,23 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
||||
initial = data[31];
|
||||
}
|
||||
for (unsigned int i = 0; i < ngasmixes; ++i) {
|
||||
gasmix[i].id = i + 1;
|
||||
gasmix[i].oxygen = data[25 + 2 * i];
|
||||
gasmix[i].helium = 0;
|
||||
gasmix[i].type = 0;
|
||||
gasmix[i].enabled = 1;
|
||||
gasmix[i].active = 0;
|
||||
gasmix[i].diluent = 0;
|
||||
}
|
||||
} else if (version == 0x23 || version == 0x24) {
|
||||
ngasmixes = 5;
|
||||
for (unsigned int i = 0; i < ngasmixes; ++i) {
|
||||
gasmix[i].id = i + 1;
|
||||
gasmix[i].oxygen = data[28 + 4 * i + 0];
|
||||
gasmix[i].helium = data[28 + 4 * i + 1];
|
||||
gasmix[i].type = data[28 + 4 * i + 3];
|
||||
gasmix[i].enabled = gasmix[i].type != 0;
|
||||
gasmix[i].active = 0;
|
||||
gasmix[i].diluent = ccr;
|
||||
// Find the first gas marked as the initial gas.
|
||||
if (initial == UNDEFINED && data[28 + 4 * i + 3] == 1) {
|
||||
@ -346,6 +362,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
||||
initial = data[31];
|
||||
}
|
||||
for (unsigned int i = 0; i < ngasmixes; ++i) {
|
||||
gasmix[i].id = i + 1;
|
||||
gasmix[i].oxygen = data[19 + 2 * i + 0];
|
||||
gasmix[i].helium = data[19 + 2 * i + 1];
|
||||
gasmix[i].type = 0;
|
||||
@ -354,6 +371,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
||||
} else {
|
||||
gasmix[i].enabled = 1;
|
||||
}
|
||||
gasmix[i].active = 0;
|
||||
gasmix[i].diluent = ccr;
|
||||
}
|
||||
}
|
||||
@ -362,7 +380,6 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
||||
ERROR(abstract->context, "Invalid initial gas mix.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
initial--; /* Convert to a zero based index. */
|
||||
} else {
|
||||
WARNING(abstract->context, "No initial gas mix available.");
|
||||
}
|
||||
@ -373,6 +390,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
||||
parser->layout = layout;
|
||||
parser->ngasmixes = ngasmixes;
|
||||
parser->nfixed = ngasmixes;
|
||||
parser->ndisabled = 0;
|
||||
parser->initial = initial;
|
||||
parser->initial_setpoint = initial_setpoint;
|
||||
parser->initial_cns = initial_cns;
|
||||
@ -385,7 +403,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int hwos, unsigned int model)
|
||||
hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int hwos, unsigned int model, unsigned int serial)
|
||||
{
|
||||
hw_ostc_parser_t *parser = NULL;
|
||||
|
||||
@ -393,7 +411,7 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (hw_ostc_parser_t *) dc_parser_allocate (context, &hw_ostc_parser_vtable);
|
||||
parser = (hw_ostc_parser_t *) dc_parser_allocate (context, &hw_ostc_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -408,14 +426,17 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign
|
||||
parser->layout = NULL;
|
||||
parser->ngasmixes = 0;
|
||||
parser->nfixed = 0;
|
||||
parser->ndisabled = 0;
|
||||
parser->initial = 0;
|
||||
parser->initial_setpoint = 0;
|
||||
parser->initial_cns = 0;
|
||||
for (unsigned int i = 0; i < NGASMIXES; ++i) {
|
||||
parser->gasmix[i].id = 0;
|
||||
parser->gasmix[i].oxygen = 0;
|
||||
parser->gasmix[i].helium = 0;
|
||||
parser->gasmix[i].type = 0;
|
||||
parser->gasmix[i].enabled = 0;
|
||||
parser->gasmix[i].active = 0;
|
||||
parser->gasmix[i].diluent = 0;
|
||||
}
|
||||
parser->serial = serial;
|
||||
@ -427,44 +448,17 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign
|
||||
|
||||
|
||||
dc_status_t
|
||||
hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial)
|
||||
hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int serial)
|
||||
{
|
||||
return hw_ostc_parser_create_internal (out, context, serial, 0, 0);
|
||||
return hw_ostc_parser_create_internal (out, context, data, size, 0, 0, serial);
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int model)
|
||||
hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model, unsigned int serial)
|
||||
{
|
||||
return hw_ostc_parser_create_internal (out, context, serial, 1, model);
|
||||
return hw_ostc_parser_create_internal (out, context, data, size, 1, model, serial);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
hw_ostc_parser_t *parser = (hw_ostc_parser_t *) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 0;
|
||||
parser->version = 0;
|
||||
parser->header = 0;
|
||||
parser->layout = NULL;
|
||||
parser->ngasmixes = 0;
|
||||
parser->nfixed = 0;
|
||||
parser->initial = 0;
|
||||
parser->initial_setpoint = 0;
|
||||
parser->initial_cns = 0;
|
||||
for (unsigned int i = 0; i < NGASMIXES; ++i) {
|
||||
parser->gasmix[i].oxygen = 0;
|
||||
parser->gasmix[i].helium = 0;
|
||||
parser->gasmix[i].type = 0;
|
||||
parser->gasmix[i].enabled = 0;
|
||||
parser->gasmix[i].diluent = 0;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -525,7 +519,7 @@ hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#define BUFLEN 32
|
||||
#define BUFLEN 64
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
|
||||
@ -540,7 +534,7 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
||||
|
||||
// Cache the profile data.
|
||||
if (parser->cached < PROFILE) {
|
||||
rc = hw_ostc_parser_samples_foreach (abstract, NULL, NULL);
|
||||
rc = hw_ostc_parser_internal_foreach (parser, NULL, NULL);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
}
|
||||
@ -571,13 +565,34 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((double *) value) = array_uint16_le (data + layout->avgdepth) / 100.0;
|
||||
break;
|
||||
case DC_FIELD_TANK_COUNT:
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
if (flags >= parser->ngasmixes) {
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
gasmix->usage = parser->gasmix[flags].diluent ?
|
||||
DC_USAGE_DILUENT : DC_USAGE_OPEN_CIRCUIT;
|
||||
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_TANK:
|
||||
if (flags >= parser->ngasmixes || !parser->gasmix[flags].enabled) {
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
dc_tank_t *tank = (dc_tank_t *) value;
|
||||
|
||||
tank->volume = 0.0;
|
||||
tank->gasmix = flags;
|
||||
tank->workpressure = 0.0;
|
||||
tank->type = DC_TANKINFO_METRIC;
|
||||
|
||||
break;
|
||||
case DC_FIELD_SALINITY:
|
||||
if (salinity < 100 || salinity > 104)
|
||||
@ -800,18 +815,34 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
static void hw_ostc_notify_bailout(hw_ostc_parser_t *parser, const unsigned char *data, unsigned int index, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
hw_ostc_parser_t *parser = (hw_ostc_parser_t *) abstract;
|
||||
if (parser->current_divemode_ccr != parser->gasmix[index].diluent) {
|
||||
dc_sample_value_t sample = {
|
||||
.event.type = SAMPLE_EVENT_STRING,
|
||||
.event.flags = SAMPLE_FLAGS_SEVERITY_INFO,
|
||||
};
|
||||
if (parser->gasmix[index].diluent) {
|
||||
sample.event.name = "Switched to closed circuit";
|
||||
} else {
|
||||
sample.event.name = "Switched to open circuit bailout";
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback(DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
parser->current_divemode_ccr = parser->gasmix[index].diluent;
|
||||
}
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
dc_parser_t *abstract = (dc_parser_t *) parser;
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
// Cache the parser data.
|
||||
dc_status_t rc = hw_ostc_parser_cache (parser);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
unsigned int version = parser->version;
|
||||
unsigned int header = parser->header;
|
||||
const hw_ostc_layout_t *layout = parser->layout;
|
||||
@ -914,10 +945,11 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
|
||||
// Get the CCR mode.
|
||||
unsigned int ccr = hw_ostc_is_ccr (divemode, version);
|
||||
parser->current_divemode_ccr = ccr;
|
||||
|
||||
unsigned int time = 0;
|
||||
unsigned int nsamples = 0;
|
||||
unsigned int tank = parser->initial != UNDEFINED ? parser->initial : 0;
|
||||
unsigned int tank = parser->initial != UNDEFINED ? parser->initial - 1 : 0;
|
||||
|
||||
unsigned int offset = header;
|
||||
if (version == 0x23 || version == 0x24)
|
||||
@ -929,31 +961,33 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
|
||||
// Time (seconds).
|
||||
time += samplerate;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Initial gas mix.
|
||||
if (time == samplerate && parser->initial != UNDEFINED) {
|
||||
sample.gasmix = parser->initial;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
unsigned int idx = hw_ostc_find_gasmix_fixed (parser, parser->initial);
|
||||
parser->gasmix[idx].active = 1;
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
}
|
||||
|
||||
// Initial setpoint (mbar).
|
||||
if (time == samplerate && parser->initial_setpoint != UNDEFINED) {
|
||||
sample.setpoint = parser->initial_setpoint / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||
}
|
||||
|
||||
// Initial CNS (%).
|
||||
if (time == samplerate && parser->initial_cns != UNDEFINED) {
|
||||
sample.cns = parser->initial_cns / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata);
|
||||
}
|
||||
|
||||
// Depth (1/100 m).
|
||||
unsigned int depth = array_uint16_le (data + offset);
|
||||
sample.depth = depth / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
offset += 2;
|
||||
|
||||
// Extended sample info.
|
||||
@ -1012,7 +1046,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
break;
|
||||
}
|
||||
if (sample.event.type && callback)
|
||||
callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
|
||||
// Manual Gas Set & Change
|
||||
if (events & 0x10) {
|
||||
@ -1021,23 +1055,35 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
unsigned int o2 = data[offset];
|
||||
unsigned int diluent;
|
||||
if (parser->model == OSTC4) {
|
||||
// all manually added gas mixes on OSTC4 are OC gases
|
||||
diluent = 0;
|
||||
} else {
|
||||
diluent = ccr;
|
||||
}
|
||||
unsigned int he = data[offset + 1];
|
||||
unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, ccr, MANUAL);
|
||||
unsigned int idx = hw_ostc_find_gasmix_manual (parser, o2, he, diluent);
|
||||
if (idx >= parser->ngasmixes) {
|
||||
if (idx >= NGASMIXES) {
|
||||
ERROR (abstract->context, "Maximum number of gas mixes reached.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
parser->gasmix[idx].id = 0;
|
||||
parser->gasmix[idx].oxygen = o2;
|
||||
parser->gasmix[idx].helium = he;
|
||||
parser->gasmix[idx].type = 0;
|
||||
parser->gasmix[idx].enabled = 1;
|
||||
parser->gasmix[idx].diluent = ccr;
|
||||
parser->gasmix[idx].active = 1;
|
||||
parser->gasmix[idx].diluent = diluent;
|
||||
parser->ngasmixes = idx + 1;
|
||||
}
|
||||
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
|
||||
hw_ostc_notify_bailout(parser, data, idx, callback, userdata);
|
||||
|
||||
offset += 2;
|
||||
length -= 2;
|
||||
}
|
||||
@ -1048,15 +1094,23 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
unsigned int idx = data[offset];
|
||||
if (idx < 1 || idx > parser->nfixed) {
|
||||
ERROR(abstract->context, "Invalid gas mix (%u).", idx);
|
||||
unsigned int id = data[offset];
|
||||
if (id > parser->nfixed && id <= parser->nfixed + OSTC4_CC_DILUENT_GAS_OFFSET) {
|
||||
// OSTC4 reports gas changes to another diluent with an offset
|
||||
id -= OSTC4_CC_DILUENT_GAS_OFFSET;
|
||||
}
|
||||
if (id < 1 || id > parser->nfixed) {
|
||||
ERROR(abstract->context, "Invalid gas mix (%u).", id);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
idx--; /* Convert to a zero based index. */
|
||||
unsigned int idx = hw_ostc_find_gasmix_fixed (parser, id);
|
||||
parser->gasmix[idx].active = 1;
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
tank = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
tank = id - 1;
|
||||
|
||||
hw_ostc_notify_bailout(parser, data, idx, callback, userdata);
|
||||
|
||||
offset++;
|
||||
length--;
|
||||
}
|
||||
@ -1069,7 +1123,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
sample.setpoint = data[offset] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||
offset++;
|
||||
length--;
|
||||
}
|
||||
@ -1083,22 +1137,27 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
|
||||
unsigned int o2 = data[offset];
|
||||
unsigned int he = data[offset + 1];
|
||||
unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, 0, MANUAL);
|
||||
unsigned int idx = hw_ostc_find_gasmix_manual (parser, o2, he, 0);
|
||||
if (idx >= parser->ngasmixes) {
|
||||
if (idx >= NGASMIXES) {
|
||||
ERROR (abstract->context, "Maximum number of gas mixes reached.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
parser->gasmix[idx].id = 0;
|
||||
parser->gasmix[idx].oxygen = o2;
|
||||
parser->gasmix[idx].helium = he;
|
||||
parser->gasmix[idx].type = 0;
|
||||
parser->gasmix[idx].enabled = 1;
|
||||
parser->gasmix[idx].active = 1;
|
||||
parser->gasmix[idx].diluent = 0;
|
||||
parser->ngasmixes = idx + 1;
|
||||
}
|
||||
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
|
||||
hw_ostc_notify_bailout(parser, data, idx, callback, userdata);
|
||||
|
||||
offset += 2;
|
||||
length -= 2;
|
||||
}
|
||||
@ -1130,7 +1189,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
case TEMPERATURE:
|
||||
value = array_uint16_le (data + offset);
|
||||
sample.temperature = value / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
break;
|
||||
case DECO:
|
||||
// Due to a firmware bug, the deco/ndl info is incorrect for
|
||||
@ -1145,7 +1204,8 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
sample.deco.depth = 0.0;
|
||||
}
|
||||
sample.deco.time = data[offset + 1] * 60;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
break;
|
||||
case PPO2:
|
||||
for (unsigned int j = 0; j < 3; ++j) {
|
||||
@ -1159,8 +1219,9 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
}
|
||||
if (count) {
|
||||
for (unsigned int j = 0; j < 3; ++j) {
|
||||
sample.ppo2 = ppo2[j] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
|
||||
sample.ppo2.sensor = i;
|
||||
sample.ppo2.value = ppo2[j] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PPO2, &sample, userdata);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1169,7 +1230,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
sample.cns = array_uint16_le (data + offset) / 100.0;
|
||||
else
|
||||
sample.cns = data[offset] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata);
|
||||
break;
|
||||
case TANK:
|
||||
value = array_uint16_le (data + offset);
|
||||
@ -1182,7 +1243,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
(firmware >= OSTC3FW(10,40) && firmware <= OSTC3FW(10,50))) {
|
||||
sample.pressure.value /= 10.0;
|
||||
}
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
}
|
||||
break;
|
||||
default: // Not yet used.
|
||||
@ -1202,7 +1263,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
sample.setpoint = data[offset] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||
offset++;
|
||||
length--;
|
||||
}
|
||||
@ -1216,22 +1277,27 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
|
||||
unsigned int o2 = data[offset];
|
||||
unsigned int he = data[offset + 1];
|
||||
unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, 0, MANUAL);
|
||||
unsigned int idx = hw_ostc_find_gasmix_manual (parser, o2, he, 0);
|
||||
if (idx >= parser->ngasmixes) {
|
||||
if (idx >= NGASMIXES) {
|
||||
ERROR (abstract->context, "Maximum number of gas mixes reached.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
parser->gasmix[idx].id = 0;
|
||||
parser->gasmix[idx].oxygen = o2;
|
||||
parser->gasmix[idx].helium = he;
|
||||
parser->gasmix[idx].type = 0;
|
||||
parser->gasmix[idx].enabled = 1;
|
||||
parser->gasmix[idx].active = 1;
|
||||
parser->gasmix[idx].diluent = 0;
|
||||
parser->ngasmixes = idx + 1;
|
||||
}
|
||||
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
|
||||
hw_ostc_notify_bailout(parser, data, idx, callback, userdata);
|
||||
|
||||
offset += 2;
|
||||
length -= 2;
|
||||
}
|
||||
@ -1249,7 +1315,50 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Remove the disabled gas mixes from the fixed gas mixes.
|
||||
unsigned int ndisabled = 0, nenabled = 0;
|
||||
unsigned int count = parser->nfixed - parser->ndisabled;
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
if (parser->gasmix[i].enabled || parser->gasmix[i].active) {
|
||||
// Move the fixed gas mix.
|
||||
parser->gasmix[nenabled] = parser->gasmix[i];
|
||||
nenabled++;
|
||||
} else {
|
||||
ndisabled++;
|
||||
}
|
||||
}
|
||||
|
||||
// Move all the manual gas mixes.
|
||||
memmove (parser->gasmix + nenabled, parser->gasmix + count,
|
||||
(parser->ngasmixes - count) * sizeof (hw_ostc_gasmix_t));
|
||||
memset (parser->gasmix + parser->ngasmixes - ndisabled, 0,
|
||||
ndisabled * sizeof (hw_ostc_gasmix_t));
|
||||
|
||||
// Adjust the counts.
|
||||
parser->ngasmixes -= ndisabled;
|
||||
parser->ndisabled += ndisabled;
|
||||
|
||||
parser->cached = PROFILE;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
hw_ostc_parser_t *parser = (hw_ostc_parser_t *) abstract;
|
||||
|
||||
// Cache the header data.
|
||||
dc_status_t rc = hw_ostc_parser_cache (parser);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
// Cache the profile data.
|
||||
if (parser->cached < PROFILE) {
|
||||
rc = hw_ostc_parser_internal_foreach (parser, NULL, NULL);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return hw_ostc_parser_internal_foreach (parser, callback, userdata);
|
||||
}
|
||||
|
||||
@ -47,7 +47,6 @@
|
||||
#include "context-private.h"
|
||||
#include "iostream-private.h"
|
||||
#include "iterator-private.h"
|
||||
#include "descriptor-private.h"
|
||||
#include "array.h"
|
||||
#include "platform.h"
|
||||
|
||||
@ -226,7 +225,7 @@ dc_irda_iterator_new (dc_iterator_t **out, dc_context_t *context, dc_descriptor_
|
||||
INFO (context, "Discover: address=%08x, name=%s, charset=%02x, hints=%04x",
|
||||
address, name, charset, hints);
|
||||
|
||||
if (!dc_descriptor_filter (descriptor, DC_TRANSPORT_IRDA, name, NULL)) {
|
||||
if (!dc_descriptor_filter (descriptor, DC_TRANSPORT_IRDA, name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
68
src/libdivecomputer.rc
Normal file
68
src/libdivecomputer.rc
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2010 Jef Driesen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <winver.h>
|
||||
|
||||
#include <libdivecomputer/version.h>
|
||||
|
||||
#ifdef HAVE_VERSION_SUFFIX
|
||||
#include "revision.h"
|
||||
#endif
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION DC_VERSION_MAJOR,DC_VERSION_MINOR,DC_VERSION_MICRO,0
|
||||
PRODUCTVERSION DC_VERSION_MAJOR,DC_VERSION_MINOR,DC_VERSION_MICRO,0
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef HAVE_VERSION_SUFFIX
|
||||
FILEFLAGS VS_FF_PRERELEASE
|
||||
#else
|
||||
FILEFLAGS 0
|
||||
#endif
|
||||
FILEOS VOS__WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE 0
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904B0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "The libdivecomputer developers"
|
||||
VALUE "FileDescription", "A library for communication with various dive computers."
|
||||
VALUE "FileVersion", DC_VERSION
|
||||
VALUE "InternalName", "libdivecomputer"
|
||||
VALUE "LegalCopyright", "Copyright © 2010 Jef Driesen"
|
||||
VALUE "OriginalFilename", "libdivecomputer.dll"
|
||||
VALUE "ProductName", "libdivecomputer"
|
||||
VALUE "ProductVersion", DC_VERSION
|
||||
#ifdef HAVE_VERSION_SUFFIX
|
||||
VALUE "Comments", DC_VERSION_REVISION
|
||||
#endif
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 1033, 1200
|
||||
END
|
||||
END
|
||||
@ -1,45 +0,0 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <winver.h>
|
||||
|
||||
#ifdef HAVE_VERSION_SUFFIX
|
||||
#include "revision.h"
|
||||
#endif
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION @DC_VERSION_MAJOR@,@DC_VERSION_MINOR@,@DC_VERSION_MICRO@,0
|
||||
PRODUCTVERSION @DC_VERSION_MAJOR@,@DC_VERSION_MINOR@,@DC_VERSION_MICRO@,0
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef HAVE_VERSION_SUFFIX
|
||||
FILEFLAGS VS_FF_PRERELEASE
|
||||
#else
|
||||
FILEFLAGS 0
|
||||
#endif
|
||||
FILEOS VOS__WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE 0
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904B0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "The libdivecomputer developers"
|
||||
VALUE "FileDescription", "A library for communication with various dive computers."
|
||||
VALUE "FileVersion", "@VERSION@"
|
||||
VALUE "InternalName", "libdivecomputer"
|
||||
VALUE "LegalCopyright", "Copyright © 2010 Jef Driesen"
|
||||
VALUE "OriginalFilename", "libdivecomputer.dll"
|
||||
VALUE "ProductName", "libdivecomputer"
|
||||
VALUE "ProductVersion", "@VERSION@"
|
||||
#ifdef HAVE_VERSION_SUFFIX
|
||||
VALUE "Comments", DC_VERSION_REVISION
|
||||
#endif
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 1033, 1200
|
||||
END
|
||||
END
|
||||
@ -34,6 +34,7 @@ dc_descriptor_get_product
|
||||
dc_descriptor_get_type
|
||||
dc_descriptor_get_model
|
||||
dc_descriptor_get_transports
|
||||
dc_descriptor_filter
|
||||
|
||||
dc_iostream_get_transport
|
||||
dc_iostream_set_timeout
|
||||
@ -93,17 +94,11 @@ dc_parser_set_clock
|
||||
dc_parser_set_atmospheric
|
||||
dc_parser_set_density
|
||||
dc_parser_get_type
|
||||
dc_parser_set_data
|
||||
dc_parser_get_datetime
|
||||
dc_parser_get_field
|
||||
dc_parser_samples_foreach
|
||||
dc_parser_destroy
|
||||
|
||||
reefnet_sensus_parser_set_calibration
|
||||
reefnet_sensuspro_parser_set_calibration
|
||||
reefnet_sensusultra_parser_set_calibration
|
||||
atomics_cobalt_parser_set_calibration
|
||||
|
||||
dc_device_open
|
||||
dc_device_close
|
||||
dc_device_dump
|
||||
|
||||
@ -158,7 +158,7 @@ liquivision_lynx_recv (liquivision_lynx_device_t *device, unsigned char data[],
|
||||
|
||||
// Verify the checksum.
|
||||
unsigned short crc = array_uint16_be (packet + 1 + size);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (packet + 1, size, 0xffff);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (packet + 1, size, 0xffff, 0x0000);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected answer checksum (%04x %04x).", crc, ccrc);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
@ -528,7 +528,7 @@ liquivision_lynx_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
memcpy (header + 0, device->info + 2, 4);
|
||||
memcpy (header + 4, logbook + offset + 4, headersize - 4);
|
||||
unsigned int crc = array_uint32_le (logbook + offset + 0);
|
||||
unsigned int ccrc = checksum_crc32b (header, headersize - unused);
|
||||
unsigned int ccrc = checksum_crc32 (header, headersize - unused);
|
||||
if (crc != ccrc) {
|
||||
WARNING (abstract->context, "Invalid dive checksum (%08x %08x)", crc, ccrc);
|
||||
status = DC_STATUS_DATAFORMAT;
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
liquivision_lynx_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
liquivision_lynx_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
liquivision_lynx_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -117,7 +117,6 @@ struct liquivision_lynx_parser_t {
|
||||
liquivision_lynx_tank_t tank[NTANKS];
|
||||
};
|
||||
|
||||
static dc_status_t liquivision_lynx_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t liquivision_lynx_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t liquivision_lynx_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t liquivision_lynx_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -125,7 +124,6 @@ static dc_status_t liquivision_lynx_parser_samples_foreach (dc_parser_t *abstrac
|
||||
static const dc_parser_vtable_t liquivision_lynx_parser_vtable = {
|
||||
sizeof(liquivision_lynx_parser_t),
|
||||
DC_FAMILY_LIQUIVISION_LYNX,
|
||||
liquivision_lynx_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -137,7 +135,7 @@ static const dc_parser_vtable_t liquivision_lynx_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
liquivision_lynx_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
liquivision_lynx_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
{
|
||||
liquivision_lynx_parser_t *parser = NULL;
|
||||
|
||||
@ -145,7 +143,7 @@ liquivision_lynx_parser_create (dc_parser_t **out, dc_context_t *context, unsign
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (liquivision_lynx_parser_t *) dc_parser_allocate (context, &liquivision_lynx_parser_vtable);
|
||||
parser = (liquivision_lynx_parser_t *) dc_parser_allocate (context, &liquivision_lynx_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -173,29 +171,6 @@ liquivision_lynx_parser_create (dc_parser_t **out, dc_context_t *context, unsign
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
liquivision_lynx_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
liquivision_lynx_parser_t *parser = (liquivision_lynx_parser_t *) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 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
|
||||
liquivision_lynx_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -315,6 +290,7 @@ liquivision_lynx_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = parser->gasmix[flags].helium / 100.0;
|
||||
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -329,6 +305,7 @@ liquivision_lynx_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
tank->beginpressure = parser->tank[flags].beginpressure / 100.0;
|
||||
tank->endpressure = parser->tank[flags].endpressure / 100.0;
|
||||
tank->gasmix = DC_GASMIX_UNKNOWN;
|
||||
tank->usage = DC_TANK_USAGE_NONE;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
@ -545,29 +522,29 @@ liquivision_lynx_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
|
||||
// Time (seconds).
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/100 m).
|
||||
sample.depth = value / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Temperature (1/10 °C).
|
||||
int temperature = (signed short) array_uint16_le (data + offset);
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
// Gas mix
|
||||
if (have_gasmix) {
|
||||
sample.gasmix = gasmix_idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
have_gasmix = 0;
|
||||
}
|
||||
|
||||
// Setpoint (1/10 bar).
|
||||
if (have_setpoint) {
|
||||
sample.setpoint = setpoint / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||
have_setpoint = 0;
|
||||
}
|
||||
|
||||
@ -577,7 +554,7 @@ liquivision_lynx_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
if (have_pressure & (1 << i)) {
|
||||
sample.pressure.tank = i;
|
||||
sample.pressure.value = pressure[i] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
}
|
||||
}
|
||||
have_pressure = 0;
|
||||
@ -593,7 +570,8 @@ liquivision_lynx_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
sample.deco.depth = 0.0;
|
||||
}
|
||||
sample.deco.time = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
have_deco = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
mares_darwin_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
|
||||
|
||||
dc_status_t
|
||||
mares_darwin_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
mares_darwin_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -47,7 +47,6 @@ struct mares_darwin_parser_t {
|
||||
unsigned int samplesize;
|
||||
};
|
||||
|
||||
static dc_status_t mares_darwin_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t mares_darwin_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t mares_darwin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -55,7 +54,6 @@ static dc_status_t mares_darwin_parser_samples_foreach (dc_parser_t *abstract, d
|
||||
static const dc_parser_vtable_t mares_darwin_parser_vtable = {
|
||||
sizeof(mares_darwin_parser_t),
|
||||
DC_FAMILY_MARES_DARWIN,
|
||||
mares_darwin_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -67,7 +65,7 @@ static const dc_parser_vtable_t mares_darwin_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
mares_darwin_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
mares_darwin_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
{
|
||||
mares_darwin_parser_t *parser = NULL;
|
||||
|
||||
@ -75,7 +73,7 @@ mares_darwin_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (mares_darwin_parser_t *) dc_parser_allocate (context, &mares_darwin_parser_vtable);
|
||||
parser = (mares_darwin_parser_t *) dc_parser_allocate (context, &mares_darwin_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -97,13 +95,6 @@ mares_darwin_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
mares_darwin_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
mares_darwin_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -159,6 +150,7 @@ mares_darwin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.0;
|
||||
if (mode == NITROX) {
|
||||
gasmix->oxygen = p[0x0E] / 100.0;
|
||||
@ -185,6 +177,7 @@ mares_darwin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
|
||||
tank->gasmix = 0;
|
||||
tank->beginpressure = array_uint16_be (p + 0x17);
|
||||
tank->endpressure = array_uint16_be (p + 0x19);
|
||||
tank->usage = DC_TANK_USAGE_NONE;
|
||||
} else {
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
@ -242,17 +235,17 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
|
||||
// Surface Time (seconds).
|
||||
time += 20;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Gas change.
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
@ -262,7 +255,7 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = ascent;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
// Deco violation
|
||||
@ -271,7 +264,7 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = 0;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
// Deco stop
|
||||
@ -282,7 +275,8 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
}
|
||||
sample.deco.time = 0;
|
||||
sample.deco.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
|
||||
if (parser->samplesize == 3) {
|
||||
unsigned int type = (time / 20 + 2) % 3;
|
||||
@ -291,7 +285,7 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
pressure -= abstract->data[offset + 2];
|
||||
sample.pressure.tank = 0;
|
||||
sample.pressure.value = pressure;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,6 @@
|
||||
|
||||
#include <string.h> // memcpy, memcmp
|
||||
#include <stdlib.h> // malloc, free
|
||||
#include <assert.h> // assert
|
||||
|
||||
#include "mares_iconhd.h"
|
||||
#include "context-private.h"
|
||||
@ -29,6 +28,7 @@
|
||||
#include "array.h"
|
||||
#include "rbstream.h"
|
||||
#include "platform.h"
|
||||
#include "packet.h"
|
||||
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &mares_iconhd_device_vtable)
|
||||
|
||||
@ -93,16 +93,13 @@ typedef struct mares_iconhd_device_t {
|
||||
unsigned char version[140];
|
||||
unsigned int model;
|
||||
unsigned int packetsize;
|
||||
unsigned char cache[20];
|
||||
unsigned int available;
|
||||
unsigned int offset;
|
||||
unsigned int splitcommand;
|
||||
} mares_iconhd_device_t;
|
||||
|
||||
static dc_status_t mares_iconhd_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||
static dc_status_t mares_iconhd_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size);
|
||||
static dc_status_t mares_iconhd_device_dump (dc_device_t *abstract, dc_buffer_t *buffer);
|
||||
static dc_status_t mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
||||
static dc_status_t mares_iconhd_device_close (dc_device_t *abstract);
|
||||
|
||||
static const dc_device_vtable_t mares_iconhd_device_vtable = {
|
||||
sizeof(mares_iconhd_device_t),
|
||||
@ -113,7 +110,7 @@ static const dc_device_vtable_t mares_iconhd_device_vtable = {
|
||||
mares_iconhd_device_dump, /* dump */
|
||||
mares_iconhd_device_foreach, /* foreach */
|
||||
NULL, /* timesync */
|
||||
NULL /* close */
|
||||
mares_iconhd_device_close /* close */
|
||||
};
|
||||
|
||||
static const mares_iconhd_layout_t mares_iconhd_layout = {
|
||||
@ -178,104 +175,41 @@ mares_iconhd_get_model (mares_iconhd_device_t *device)
|
||||
return model;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_read (mares_iconhd_device_t *device, unsigned char data[], size_t size)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
|
||||
|
||||
size_t nbytes = 0;
|
||||
while (nbytes < size) {
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
if (device->available == 0) {
|
||||
// Read a packet into the cache.
|
||||
size_t len = 0;
|
||||
rc = dc_iostream_read (device->iostream, device->cache, sizeof(device->cache), &len);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
device->available = len;
|
||||
device->offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the minimum packet size.
|
||||
size_t length = (transport == DC_TRANSPORT_BLE) ? device->available : size - nbytes;
|
||||
|
||||
// Limit the packet size to the total size.
|
||||
if (nbytes + length > size)
|
||||
length = size - nbytes;
|
||||
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
// Copy the data from the cached packet.
|
||||
memcpy (data + nbytes, device->cache + device->offset, length);
|
||||
device->available -= length;
|
||||
device->offset += length;
|
||||
} else {
|
||||
// Read the packet.
|
||||
rc = dc_iostream_read (device->iostream, data + nbytes, length, &length);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
}
|
||||
|
||||
nbytes += length;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_write (mares_iconhd_device_t *device, const unsigned char data[], size_t size)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
|
||||
|
||||
size_t nbytes = 0;
|
||||
while (nbytes < size) {
|
||||
// Set the maximum packet size.
|
||||
size_t length = (transport == DC_TRANSPORT_BLE) ? sizeof(device->cache) : size - nbytes;
|
||||
|
||||
// Limit the packet size to the total size.
|
||||
if (nbytes + length > size)
|
||||
length = size - nbytes;
|
||||
|
||||
// Write the packet.
|
||||
rc = dc_iostream_write (device->iostream, data + nbytes, length, &length);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
nbytes += length;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_packet (mares_iconhd_device_t *device,
|
||||
const unsigned char command[], unsigned int csize,
|
||||
unsigned char cmd,
|
||||
const unsigned char data[], unsigned int size,
|
||||
unsigned char answer[], unsigned int asize)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
unsigned int split_csize;
|
||||
|
||||
assert (csize >= 2);
|
||||
dc_transport_t transport = dc_iostream_get_transport (device->iostream);
|
||||
|
||||
if (device_is_cancelled (abstract))
|
||||
return DC_STATUS_CANCELLED;
|
||||
|
||||
split_csize = device->splitcommand ? 2 : csize;
|
||||
|
||||
// Send the command header to the dive computer.
|
||||
status = mares_iconhd_write (device, command, split_csize);
|
||||
const unsigned char command[2] = {
|
||||
cmd, cmd ^ XOR,
|
||||
};
|
||||
status = dc_iostream_write (device->iostream, command, sizeof(command), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Send the command payload to the dive computer.
|
||||
if (size && transport == DC_TRANSPORT_BLE) {
|
||||
status = dc_iostream_write (device->iostream, data, size, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// Receive the header byte.
|
||||
unsigned char header[1] = {0};
|
||||
status = mares_iconhd_read (device, header, sizeof (header));
|
||||
status = dc_iostream_read (device->iostream, header, sizeof (header), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the answer.");
|
||||
return status;
|
||||
@ -287,17 +221,17 @@ mares_iconhd_packet (mares_iconhd_device_t *device,
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Send any remaining command payload to the dive computer.
|
||||
if (csize > split_csize) {
|
||||
status = mares_iconhd_write (device, command + split_csize, csize - split_csize);
|
||||
// Send the command payload to the dive computer.
|
||||
if (size && transport != DC_TRANSPORT_BLE) {
|
||||
status = dc_iostream_write (device->iostream, data, size, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
ERROR (abstract->context, "Failed to send the command data.");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the packet.
|
||||
status = mares_iconhd_read (device, answer, asize);
|
||||
status = dc_iostream_read (device->iostream, answer, asize, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the answer.");
|
||||
return status;
|
||||
@ -305,7 +239,7 @@ mares_iconhd_packet (mares_iconhd_device_t *device,
|
||||
|
||||
// Receive the trailer byte.
|
||||
unsigned char trailer[1] = {0};
|
||||
status = mares_iconhd_read (device, trailer, sizeof (trailer));
|
||||
status = dc_iostream_read (device->iostream, trailer, sizeof (trailer), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the answer.");
|
||||
return status;
|
||||
@ -321,11 +255,11 @@ mares_iconhd_packet (mares_iconhd_device_t *device,
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_transfer (mares_iconhd_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize)
|
||||
mares_iconhd_transfer (mares_iconhd_device_t *device, unsigned char cmd, const unsigned char data[], unsigned int size, unsigned char answer[], unsigned int asize)
|
||||
{
|
||||
unsigned int nretries = 0;
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
while ((rc = mares_iconhd_packet (device, command, csize, answer, asize)) != DC_STATUS_SUCCESS) {
|
||||
while ((rc = mares_iconhd_packet (device, cmd, data, size, answer, asize)) != DC_STATUS_SUCCESS) {
|
||||
// Automatically discard a corrupted packet,
|
||||
// and request a new one.
|
||||
if (rc != DC_STATUS_PROTOCOL && rc != DC_STATUS_TIMEOUT)
|
||||
@ -338,8 +272,6 @@ mares_iconhd_transfer (mares_iconhd_device_t *device, const unsigned char comman
|
||||
// Discard any garbage bytes.
|
||||
dc_iostream_sleep (device->iostream, 100);
|
||||
dc_iostream_purge (device->iostream, DC_DIRECTION_INPUT);
|
||||
device->available = 0;
|
||||
device->offset = 0;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
@ -362,23 +294,21 @@ mares_iconhd_read_object(mares_iconhd_device_t *device, dc_event_progress_t *pro
|
||||
|
||||
// Transfer the init packet.
|
||||
unsigned char rsp_init[16];
|
||||
unsigned char cmd_init[18] = {
|
||||
CMD_OBJ_INIT,
|
||||
CMD_OBJ_INIT ^ XOR,
|
||||
unsigned char cmd_init[16] = {
|
||||
0x40,
|
||||
(index >> 0) & 0xFF,
|
||||
(index >> 8) & 0xFF,
|
||||
subindex & 0xFF
|
||||
};
|
||||
memset (cmd_init + 6, 0x00, sizeof(cmd_init) - 6);
|
||||
status = mares_iconhd_transfer (device, cmd_init, sizeof (cmd_init), rsp_init, sizeof (rsp_init));
|
||||
status = mares_iconhd_transfer (device, CMD_OBJ_INIT, cmd_init, sizeof (cmd_init), rsp_init, sizeof (rsp_init));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to transfer the init packet.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Verify the packet header.
|
||||
if (memcmp (cmd_init + 3, rsp_init + 1, 3) != 0) {
|
||||
if (memcmp (cmd_init + 1, rsp_init + 1, 3) != 0) {
|
||||
ERROR (abstract->context, "Unexpected packet header.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
@ -426,8 +356,7 @@ mares_iconhd_read_object(mares_iconhd_device_t *device, dc_event_progress_t *pro
|
||||
|
||||
// Transfer the segment packet.
|
||||
unsigned char rsp_segment[1 + 504];
|
||||
unsigned char cmd_segment[] = {cmd, cmd ^ XOR};
|
||||
status = mares_iconhd_transfer (device, cmd_segment, sizeof (cmd_segment), rsp_segment, len + 1);
|
||||
status = mares_iconhd_transfer (device, cmd, NULL, 0, rsp_segment, len + 1);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to transfer the segment packet.");
|
||||
return status;
|
||||
@ -463,6 +392,7 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
mares_iconhd_device_t *device = NULL;
|
||||
dc_transport_t transport = dc_iostream_get_transport (iostream);
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
@ -475,63 +405,60 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
device->iostream = iostream;
|
||||
device->layout = NULL;
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
device->fingerprint_size = sizeof (device->fingerprint);
|
||||
memset (device->version, 0, sizeof (device->version));
|
||||
device->model = 0;
|
||||
device->packetsize = 0;
|
||||
memset (device->cache, 0, sizeof (device->cache));
|
||||
device->available = 0;
|
||||
device->offset = 0;
|
||||
|
||||
/*
|
||||
* At least the Mares Matrix needs the command to be split into
|
||||
* base and argument, with a wait for the ACK byte in between.
|
||||
*
|
||||
* See commit 59bfb0f3189b ("Add support for the Mares Matrix")
|
||||
* for details.
|
||||
*/
|
||||
device->splitcommand = 1;
|
||||
// Create the packet stream.
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
status = dc_packet_open (&device->iostream, context, iostream, 20, 20);
|
||||
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 8E1).
|
||||
status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_EVEN, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the terminal attributes.");
|
||||
goto error_free;
|
||||
goto error_free_iostream;
|
||||
}
|
||||
|
||||
// Set the timeout for receiving data (3000 ms).
|
||||
status = dc_iostream_set_timeout (device->iostream, 3000);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the timeout.");
|
||||
goto error_free;
|
||||
goto error_free_iostream;
|
||||
}
|
||||
|
||||
// Clear the DTR line.
|
||||
status = dc_iostream_set_dtr (device->iostream, 0);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to clear the DTR line.");
|
||||
goto error_free;
|
||||
goto error_free_iostream;
|
||||
}
|
||||
|
||||
// Clear the RTS line.
|
||||
status = dc_iostream_set_rts (device->iostream, 0);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to clear the RTS line.");
|
||||
goto error_free;
|
||||
goto error_free_iostream;
|
||||
}
|
||||
|
||||
// Make sure everything is in a sane state.
|
||||
dc_iostream_purge (device->iostream, DC_DIRECTION_ALL);
|
||||
|
||||
// Send the version command.
|
||||
unsigned char command[] = {CMD_VERSION, CMD_VERSION ^ XOR};
|
||||
status = mares_iconhd_transfer (device, command, sizeof (command),
|
||||
status = mares_iconhd_transfer (device, CMD_VERSION, NULL, 0,
|
||||
device->version, sizeof (device->version));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
goto error_free;
|
||||
goto error_free_iostream;
|
||||
}
|
||||
|
||||
// Autodetect the model using the version packet.
|
||||
@ -540,9 +467,8 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_
|
||||
// Read the size of the flash memory.
|
||||
unsigned int memsize = 0;
|
||||
if (device->model == QUAD) {
|
||||
unsigned char cmd_flash[] = {CMD_FLASHSIZE, CMD_FLASHSIZE ^ XOR};
|
||||
unsigned char rsp_flash[4] = {0};
|
||||
status = mares_iconhd_transfer (device, cmd_flash, sizeof (cmd_flash), rsp_flash, sizeof (rsp_flash));
|
||||
status = mares_iconhd_transfer (device, CMD_FLASHSIZE, NULL, 0, rsp_flash, sizeof (rsp_flash));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
WARNING (context, "Failed to read the flash memory size.");
|
||||
} else {
|
||||
@ -605,26 +531,37 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_
|
||||
*/
|
||||
if (device->packetsize > 128)
|
||||
device->packetsize = 128;
|
||||
/*
|
||||
* With BLE, don't wait for ACK before sending the arguments
|
||||
* to a command.
|
||||
*
|
||||
* There is some timing issue that makes that take too long
|
||||
* and causes the command to be aborted.
|
||||
*/
|
||||
device->splitcommand = 0;
|
||||
}
|
||||
|
||||
*out = (dc_device_t *) device;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
|
||||
error_free_iostream:
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
dc_iostream_close (device->iostream);
|
||||
}
|
||||
error_free:
|
||||
dc_device_deallocate ((dc_device_t *) device);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_device_close (dc_device_t *abstract)
|
||||
{
|
||||
mares_iconhd_device_t *device = (mares_iconhd_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
|
||||
mares_iconhd_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
|
||||
{
|
||||
@ -656,7 +593,7 @@ mares_iconhd_device_read (dc_device_t *abstract, unsigned int address, unsigned
|
||||
len = device->packetsize;
|
||||
|
||||
// Read the packet.
|
||||
unsigned char command[] = {CMD_READ, CMD_READ ^ XOR,
|
||||
unsigned char command[] = {
|
||||
(address ) & 0xFF,
|
||||
(address >> 8) & 0xFF,
|
||||
(address >> 16) & 0xFF,
|
||||
@ -665,7 +602,7 @@ mares_iconhd_device_read (dc_device_t *abstract, unsigned int address, unsigned
|
||||
(len >> 8) & 0xFF,
|
||||
(len >> 16) & 0xFF,
|
||||
(len >> 24) & 0xFF};
|
||||
rc = mares_iconhd_transfer (device, command, sizeof (command), data, len);
|
||||
rc = mares_iconhd_transfer (device, CMD_READ, command, sizeof (command), data, len);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
mares_iconhd_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
mares_iconhd_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model, unsigned int serial);
|
||||
mares_iconhd_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model, unsigned int serial);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -267,7 +267,6 @@ static const mares_iconhd_layout_t horizon = {
|
||||
0x54 + 8, /* tanks */
|
||||
};
|
||||
|
||||
static dc_status_t mares_iconhd_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -275,7 +274,6 @@ static dc_status_t mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, d
|
||||
static const dc_parser_vtable_t mares_iconhd_parser_vtable = {
|
||||
sizeof(mares_iconhd_parser_t),
|
||||
DC_FAMILY_MARES_ICONHD,
|
||||
mares_iconhd_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -299,7 +297,7 @@ mares_genius_isvalid (const unsigned char data[], size_t size, unsigned int type
|
||||
}
|
||||
|
||||
unsigned short crc = array_uint16_le(data + size - 6);
|
||||
unsigned short ccrc = checksum_crc16_ccitt(data + 4, size - 10, 0x0000);
|
||||
unsigned short ccrc = checksum_crc16_ccitt(data + 4, size - 10, 0x0000, 0x0000);
|
||||
if (crc != ccrc) {
|
||||
return 0;
|
||||
}
|
||||
@ -404,12 +402,12 @@ mares_iconhd_cache (mares_iconhd_parser_t *parser)
|
||||
unsigned int samplerate = 0;
|
||||
if (parser->model == SMARTAPNEA) {
|
||||
unsigned int idx = (settings & 0x0600) >> 9;
|
||||
interval = 1;
|
||||
samplerate = 1 << idx;
|
||||
interval = 1000 / samplerate;
|
||||
} else {
|
||||
const unsigned int intervals[] = {1, 5, 10, 20};
|
||||
unsigned int idx = (settings & 0x0C00) >> 10;
|
||||
interval = intervals[idx];
|
||||
interval = intervals[idx] * 1000;
|
||||
samplerate = 1;
|
||||
}
|
||||
|
||||
@ -628,7 +626,7 @@ mares_genius_cache (mares_iconhd_parser_t *parser)
|
||||
parser->headersize = headersize;
|
||||
parser->settings = settings;
|
||||
parser->surftime = surftime * 60;
|
||||
parser->interval = 5;
|
||||
parser->interval = 5000;
|
||||
parser->samplerate = 1;
|
||||
parser->ntanks = ntanks;
|
||||
parser->ngasmixes = ngasmixes;
|
||||
@ -659,7 +657,7 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser)
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model, unsigned int serial)
|
||||
mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model, unsigned int serial)
|
||||
{
|
||||
mares_iconhd_parser_t *parser = NULL;
|
||||
|
||||
@ -667,7 +665,7 @@ mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (mares_iconhd_parser_t *) dc_parser_allocate (context, &mares_iconhd_parser_vtable);
|
||||
parser = (mares_iconhd_parser_t *) dc_parser_allocate (context, &mares_iconhd_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -705,41 +703,6 @@ mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
mares_iconhd_parser_t *parser = (mares_iconhd_parser_t *) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 0;
|
||||
parser->logformat = 0;
|
||||
parser->mode = (parser->model == GENIUS || parser->model == HORIZON) ? GENIUS_AIR : ICONHD_AIR;
|
||||
parser->nsamples = 0;
|
||||
parser->samplesize = 0;
|
||||
parser->headersize = 0;
|
||||
parser->settings = 0;
|
||||
parser->surftime = 0;
|
||||
parser->interval = 0;
|
||||
parser->samplerate = 0;
|
||||
parser->ntanks = 0;
|
||||
parser->ngasmixes = 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].volume = 0;
|
||||
parser->tank[i].workpressure = 0;
|
||||
parser->tank[i].beginpressure = 0;
|
||||
parser->tank[i].endpressure = 0;
|
||||
}
|
||||
parser->layout = NULL;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -827,7 +790,7 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
|
||||
if (parser->layout->divetime != UNSUPPORTED) {
|
||||
*((unsigned int *) value) = array_uint16_le (p + parser->layout->divetime);
|
||||
} else {
|
||||
*((unsigned int *) value) = parser->nsamples * parser->interval - parser->surftime;
|
||||
*((unsigned int *) value) = parser->nsamples * parser->interval / 1000 - parser->surftime;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_MAXDEPTH:
|
||||
@ -837,6 +800,7 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
|
||||
*((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;
|
||||
@ -864,6 +828,7 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
|
||||
} else {
|
||||
tank->gasmix = DC_GASMIX_UNKNOWN;
|
||||
}
|
||||
tank->usage = DC_TANK_USAGE_NONE;
|
||||
break;
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
*((double *) value) = array_uint16_le (p + parser->layout->atmospheric) / (1000.0 * parser->layout->atmospheric_divisor);
|
||||
@ -981,14 +946,6 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
|
||||
const unsigned char *data = abstract->data;
|
||||
|
||||
if (parser->samplerate > 1) {
|
||||
// The Smart Apnea supports multiple samples per second
|
||||
// (e.g. 2, 4 or 8). Since our smallest unit of time is one
|
||||
// second, we can't represent this, and the extra samples
|
||||
// will get dropped.
|
||||
WARNING(abstract->context, "Multiple samples per second are not supported!");
|
||||
}
|
||||
|
||||
// Previous gas mix - initialize with impossible value
|
||||
unsigned int gasmix_previous = 0xFFFFFFFF;
|
||||
|
||||
@ -1039,29 +996,30 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
unsigned int surftime = array_uint16_le (data + offset + 4);
|
||||
|
||||
// Surface Time (seconds).
|
||||
time += surftime;
|
||||
time += surftime * 1000;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Surface Depth (0 m).
|
||||
sample.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
offset += parser->samplesize;
|
||||
nsamples++;
|
||||
|
||||
for (unsigned int i = 0; i < divetime; ++i) {
|
||||
unsigned int count = divetime * parser->samplerate;
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
// Time (seconds).
|
||||
time += parser->interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
unsigned int depth = array_uint16_le (data + offset);
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
offset += 2 * parser->samplerate;
|
||||
offset += 2;
|
||||
}
|
||||
} else if (parser->model != GENIUS && parser->model != HORIZON && parser->mode == ICONHD_FREEDIVE) {
|
||||
unsigned int maxdepth = array_uint16_le (data + offset + 0);
|
||||
@ -1069,22 +1027,22 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
unsigned int surftime = array_uint16_le (data + offset + 4);
|
||||
|
||||
// Surface Time (seconds).
|
||||
time += surftime;
|
||||
time += surftime * 1000;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Surface Depth (0 m).
|
||||
sample.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Dive Time (seconds).
|
||||
time += divetime;
|
||||
time += divetime * 1000;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Maximum Depth (1/10 m).
|
||||
sample.depth = maxdepth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
offset += parser->samplesize;
|
||||
nsamples++;
|
||||
@ -1142,15 +1100,15 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
// Time (seconds).
|
||||
time += parser->interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Temperature (1/10 °C).
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
// Current gas mix
|
||||
if (parser->ngasmixes > 0) {
|
||||
@ -1160,7 +1118,7 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
}
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
}
|
||||
@ -1171,7 +1129,7 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = bookmark;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
if (parser->model == GENIUS || parser->model == HORIZON) {
|
||||
@ -1184,7 +1142,8 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
sample.deco.depth = 0.0;
|
||||
}
|
||||
sample.deco.time = decotime * 60;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = tts;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
|
||||
// Alarms
|
||||
for (unsigned int v = alarms, i = 0; v; v >>= 1, ++i) {
|
||||
@ -1210,7 +1169,7 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = 0;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1231,7 +1190,7 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
if (gasmix < parser->ntanks) {
|
||||
sample.pressure.tank = gasmix;
|
||||
sample.pressure.value = pressure / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
} else if (pressure != 0) {
|
||||
WARNING (abstract->context, "Invalid tank with non-zero pressure.");
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
mares_nemo_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
mares_nemo_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
mares_nemo_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -59,7 +59,6 @@ struct mares_nemo_parser_t {
|
||||
unsigned int extra;
|
||||
};
|
||||
|
||||
static dc_status_t mares_nemo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t mares_nemo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t mares_nemo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -67,7 +66,6 @@ static dc_status_t mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_
|
||||
static const dc_parser_vtable_t mares_nemo_parser_vtable = {
|
||||
sizeof(mares_nemo_parser_t),
|
||||
DC_FAMILY_MARES_NEMO,
|
||||
mares_nemo_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -79,15 +77,16 @@ static const dc_parser_vtable_t mares_nemo_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
mares_nemo_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
mares_nemo_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
mares_nemo_parser_t *parser = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (mares_nemo_parser_t *) dc_parser_allocate (context, &mares_nemo_parser_vtable);
|
||||
parser = (mares_nemo_parser_t *) dc_parser_allocate (context, &mares_nemo_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -98,70 +97,42 @@ mares_nemo_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int
|
||||
if (model == NEMOWIDE || model == NEMOAIR || model == PUCK || model == PUCKAIR)
|
||||
freedive = GAUGE;
|
||||
|
||||
// Set the default values.
|
||||
parser->model = model;
|
||||
parser->freedive = freedive;
|
||||
parser->mode = AIR;
|
||||
parser->length = 0;
|
||||
parser->sample_count = 0;
|
||||
parser->sample_size = 0;
|
||||
parser->header = 0;
|
||||
parser->extra = 0;
|
||||
|
||||
*out = (dc_parser_t*) parser;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
mares_nemo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
mares_nemo_parser_t *parser = (mares_nemo_parser_t *) abstract;
|
||||
|
||||
// Clear the previous state.
|
||||
parser->base.data = NULL;
|
||||
parser->base.size = 0;
|
||||
parser->mode = AIR;
|
||||
parser->length = 0;
|
||||
parser->sample_count = 0;
|
||||
parser->sample_size = 0;
|
||||
parser->header = 0;
|
||||
parser->extra = 0;
|
||||
|
||||
if (size == 0)
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
if (size < 2 + 3)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
if (size < 2 + 3) {
|
||||
status = DC_STATUS_DATAFORMAT;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
unsigned int length = array_uint16_le (data);
|
||||
if (length > size)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
if (length > size) {
|
||||
status = DC_STATUS_DATAFORMAT;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
unsigned int extra = 0;
|
||||
const unsigned char marker[3] = {0xAA, 0xBB, 0xCC};
|
||||
if (memcmp (data + length - 3, marker, sizeof (marker)) == 0) {
|
||||
if (parser->model == PUCKAIR)
|
||||
if (model == PUCKAIR)
|
||||
extra = 7;
|
||||
else
|
||||
extra = 12;
|
||||
}
|
||||
|
||||
if (length < 2 + extra + 3)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
if (length < 2 + extra + 3) {
|
||||
status = DC_STATUS_DATAFORMAT;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
unsigned int mode = data[length - extra - 1];
|
||||
|
||||
unsigned int header_size = 53;
|
||||
unsigned int sample_size = 2;
|
||||
if (extra) {
|
||||
if (parser->model == PUCKAIR)
|
||||
if (model == PUCKAIR)
|
||||
sample_size = 3;
|
||||
else
|
||||
sample_size = 5;
|
||||
}
|
||||
if (mode == parser->freedive) {
|
||||
if (mode == freedive) {
|
||||
header_size = 28;
|
||||
sample_size = 6;
|
||||
}
|
||||
@ -169,12 +140,14 @@ mares_nemo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, un
|
||||
unsigned int nsamples = array_uint16_le (data + length - extra - 3);
|
||||
|
||||
unsigned int nbytes = 2 + nsamples * sample_size + header_size + extra;
|
||||
if (length != nbytes)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
if (length != nbytes) {
|
||||
status = DC_STATUS_DATAFORMAT;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Store the new state.
|
||||
parser->base.data = data;
|
||||
parser->base.size = size;
|
||||
// Set the default values.
|
||||
parser->model = model;
|
||||
parser->freedive = freedive;
|
||||
parser->mode = mode;
|
||||
parser->length = length;
|
||||
parser->sample_count = nsamples;
|
||||
@ -182,7 +155,13 @@ mares_nemo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, un
|
||||
parser->header = header_size;
|
||||
parser->extra = extra;
|
||||
|
||||
*out = (dc_parser_t*) parser;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free:
|
||||
dc_parser_deallocate ((dc_parser_t *) parser);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@ -251,6 +230,7 @@ mares_nemo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
||||
}
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
break;
|
||||
case DC_FIELD_TANK_COUNT:
|
||||
if (parser->extra)
|
||||
@ -290,6 +270,7 @@ mares_nemo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
||||
} else {
|
||||
tank->gasmix = DC_GASMIX_UNKNOWN;
|
||||
}
|
||||
tank->usage = DC_TANK_USAGE_NONE;
|
||||
break;
|
||||
case DC_FIELD_TEMPERATURE_MINIMUM:
|
||||
*((double *) value) = (signed char) p[53 - 11];
|
||||
@ -382,17 +363,17 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
|
||||
// Time (seconds).
|
||||
time += 20;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Gas change.
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
@ -402,7 +383,7 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = ascent;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
// Deco violation
|
||||
@ -411,7 +392,7 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = 0;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
// Deco stop
|
||||
@ -422,20 +403,21 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
}
|
||||
sample.deco.time = 0;
|
||||
sample.deco.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
|
||||
// Pressure (1 bar).
|
||||
if (parser->sample_size == 3) {
|
||||
sample.pressure.tank = 0;
|
||||
sample.pressure.value = data[idx + 2];
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
} else if (parser->sample_size == 5) {
|
||||
unsigned int type = (time / 20) % 3;
|
||||
if (type == 0) {
|
||||
pressure -= data[idx + 2] * 100;
|
||||
sample.pressure.tank = 0;
|
||||
sample.pressure.value = pressure / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -459,12 +441,12 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
|
||||
// Surface Time (seconds).
|
||||
time += surftime;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Surface Depth (0 m).
|
||||
sample.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
if (profiles) {
|
||||
// Get the freedive sample interval for this model.
|
||||
@ -500,12 +482,12 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
time += interval;
|
||||
if (time > maxtime)
|
||||
time = maxtime; // Adjust the last sample.
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
}
|
||||
|
||||
// Verify that the number of samples in the profile data
|
||||
@ -519,12 +501,12 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
} else {
|
||||
// Dive Time (seconds).
|
||||
time += divetime;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Maximum Depth (1/10 m).
|
||||
sample.depth = maxdepth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
#include "context-private.h"
|
||||
#include "device-private.h"
|
||||
#include "array.h"
|
||||
#include "packet.h"
|
||||
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &mclean_extreme_device_vtable)
|
||||
|
||||
@ -391,6 +392,7 @@ mclean_extreme_device_open(dc_device_t **out, dc_context_t *context, dc_iostream
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
mclean_extreme_device_t *device = NULL;
|
||||
dc_transport_t transport = dc_iostream_get_transport (iostream);
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
@ -403,21 +405,31 @@ mclean_extreme_device_open(dc_device_t **out, dc_context_t *context, dc_iostream
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
device->iostream = iostream;
|
||||
memset(device->fingerprint, 0, sizeof(device->fingerprint));
|
||||
|
||||
// Create the packet stream.
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
status = dc_packet_open (&device->iostream, context, iostream, 244, 244);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to create the packet stream.");
|
||||
goto error_free;
|
||||
}
|
||||
} else {
|
||||
device->iostream = iostream;
|
||||
}
|
||||
|
||||
// Set the serial communication protocol (115200 8N1).
|
||||
status = dc_iostream_configure(device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR(context, "Failed to set the terminal attributes.");
|
||||
goto error_free;
|
||||
goto error_free_iostream;
|
||||
}
|
||||
|
||||
// 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;
|
||||
goto error_free_iostream;
|
||||
}
|
||||
|
||||
// Make sure everything is in a sane state.
|
||||
@ -428,6 +440,10 @@ mclean_extreme_device_open(dc_device_t **out, dc_context_t *context, dc_iostream
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free_iostream:
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
dc_iostream_close (device->iostream);
|
||||
}
|
||||
error_free:
|
||||
dc_device_deallocate((dc_device_t *)device);
|
||||
return status;
|
||||
@ -438,14 +454,24 @@ mclean_extreme_device_close(dc_device_t *abstract)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
mclean_extreme_device_t *device = (mclean_extreme_device_t *)abstract;
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
|
||||
status = mclean_extreme_send(device, CMD_CLOSE, NULL, 0);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
rc = mclean_extreme_send(device, CMD_CLOSE, NULL, 0);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR(abstract->context, "Failed to send the exit command.");
|
||||
return status;
|
||||
dc_status_set_error(&status, rc);
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
// Close the packet stream.
|
||||
if (dc_iostream_get_transport (device->iostream) == DC_TRANSPORT_BLE) {
|
||||
rc = dc_iostream_close (device->iostream);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to close the packet stream.");
|
||||
dc_status_set_error(&status, rc);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user