Compare commits
396 Commits
mcLeanBLE
...
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 | ||
|
|
7efedfbb2b | ||
|
|
255a2dbb9a | ||
|
|
ee78d6f65b | ||
|
|
328812e95b | ||
|
|
98c7887e9c | ||
|
|
5fd9317533 | ||
|
|
9787bb7ac9 | ||
|
|
1b9aea3213 | ||
|
|
9a3363dc7d | ||
|
|
f03f9b3bb3 | ||
|
|
201be561d4 | ||
|
|
78373d827b | ||
|
|
4e83b1642c | ||
|
|
9eef8c50c0 | ||
|
|
86e9cc3443 | ||
|
|
3ce34a0b6d | ||
|
|
187f8d625b | ||
|
|
fca64faa3c | ||
|
|
e0e3bc8994 | ||
|
|
ceae89e149 | ||
|
|
3414f72f60 | ||
|
|
d0857c49ec | ||
|
|
f59cbf0fe5 | ||
|
|
45b9ee8376 | ||
|
|
cf81ac79b3 | ||
|
|
90bb40e5ea | ||
|
|
bf268d79b4 | ||
|
|
989c992154 | ||
|
|
b1f4ad94eb | ||
|
|
547b1cfd15 | ||
|
|
064e198315 | ||
|
|
9019805f52 | ||
|
|
f4fae1b9f6 | ||
|
|
094a225363 | ||
|
|
79c9c5b7f9 | ||
|
|
6200a7923f | ||
|
|
2129403c1e | ||
|
|
59a0844ee6 | ||
|
|
ed0b21beae | ||
|
|
755f23fdfa | ||
|
|
db2540485e | ||
|
|
2577afed55 | ||
|
|
2c5ebef594 | ||
|
|
913a65fde6 | ||
|
|
1e47f597fa | ||
|
|
5218d3921a | ||
|
|
6874130743 | ||
|
|
2f3a057969 | ||
|
|
c2102f62d6 | ||
|
|
bf93040ab1 | ||
|
|
8a6abab1da | ||
|
|
005a2501b9 | ||
|
|
9508401971 | ||
|
|
89ae8b94cf | ||
|
|
a99d990117 | ||
|
|
c578e0a158 | ||
|
|
34bc6b1613 | ||
|
|
59dd6a2a56 | ||
|
|
28c27e2392 | ||
|
|
3d388a0a96 | ||
|
|
c5813d624a | ||
|
|
3eedf4d24d | ||
|
|
3e5282bf74 | ||
|
|
43a503f6f0 | ||
|
|
4d8cdaaf8e | ||
|
|
ce578cafb9 | ||
|
|
12c77a228e | ||
|
|
6ab140461a | ||
|
|
18f06ea585 | ||
|
|
7fb943ae7f | ||
|
|
565bb2af02 | ||
|
|
95f309a1c9 | ||
|
|
107f5b14e3 | ||
|
|
391d4db419 | ||
|
|
972beb52be | ||
|
|
80f22dce0b | ||
|
|
26c43d6d8b | ||
|
|
8451286c17 | ||
|
|
be5bb9e690 | ||
|
|
e6f091909b | ||
|
|
4616e2ed21 | ||
|
|
a17e466bd1 | ||
|
|
643a6211b2 | ||
|
|
aff0c28d08 | ||
|
|
4b4efb2c07 | ||
|
|
2443d3ea47 | ||
|
|
d0c7562c41 | ||
|
|
7c3e92e391 | ||
|
|
0aad8cfd13 | ||
|
|
cd72516668 | ||
|
|
0064097c03 | ||
|
|
8bfb965589 | ||
|
|
82c0134811 | ||
|
|
4512a0a5d7 | ||
|
|
52d2684479 | ||
|
|
7e3bf7eeb8 | ||
|
|
ea051578e6 | ||
|
|
77498afe5e | ||
|
|
5f3a0f0b8a | ||
|
|
0753f10661 | ||
|
|
0448ce686a | ||
|
|
39dbb275cc | ||
|
|
bedd6180f1 | ||
|
|
c6640aa7d3 | ||
|
|
7a650f940c | ||
|
|
86e1d59a6a | ||
|
|
54fa676e75 | ||
|
|
d1242a28cf | ||
|
|
ccd37d4fa3 | ||
|
|
811a9b4f89 | ||
|
|
2794f96e47 | ||
|
|
d960a37e12 | ||
|
|
17bc0faa51 | ||
|
|
f6df075d51 | ||
|
|
c5dced237a | ||
|
|
c9c441b8bb | ||
|
|
5e2d376627 | ||
|
|
16e49eee6d | ||
|
|
70411048e5 | ||
|
|
331bcbdaf7 | ||
|
|
af03e39383 | ||
|
|
93fe31eef5 | ||
|
|
b2040d9adb | ||
|
|
cadbffe416 | ||
|
|
cd0f42804a | ||
|
|
ba4a119a4f | ||
|
|
9ff6e5caad | ||
|
|
a8bcfb998b | ||
|
|
1c39c68203 | ||
|
|
0a9b8b1318 | ||
|
|
7e075eb959 | ||
|
|
e52468e0c3 | ||
|
|
1a4798792e | ||
|
|
c4b694fdb1 | ||
|
|
b6df353752 | ||
|
|
6e40a457f3 | ||
|
|
a282ae0b29 | ||
|
|
3057ac79c2 | ||
|
|
f2cc4ab7ef | ||
|
|
75f260a941 | ||
|
|
643b4271f6 | ||
|
|
e0409a9496 | ||
|
|
70d3cdcc08 | ||
|
|
e7da5acff3 | ||
|
|
03974481b0 | ||
|
|
58d410b1a2 | ||
|
|
38bd51e63a | ||
|
|
2ef285faf3 | ||
|
|
3e87ed050c | ||
|
|
927362354d | ||
|
|
5bb6257acb | ||
|
|
060c0b7215 | ||
|
|
eaeb5c5341 | ||
|
|
5cb527d53c | ||
|
|
cfc9ddc380 | ||
|
|
cffda88ae8 | ||
|
|
b186846a9e | ||
|
|
da2446283a | ||
|
|
6645b3f5e4 | ||
|
|
c8bd477c84 | ||
|
|
c747dc7184 | ||
|
|
9307acbe4a | ||
|
|
9106250a53 | ||
|
|
449b65cf1b | ||
|
|
0bc7b195e5 | ||
|
|
fba5676b78 | ||
|
|
87d484e9a8 | ||
|
|
14fd0296d4 | ||
|
|
47cbed5355 | ||
|
|
2ccdc46561 | ||
|
|
37c4203537 | ||
|
|
9ab0800c00 | ||
|
|
d85d8811f0 | ||
|
|
76d225dcfc | ||
|
|
6ef72ab420 | ||
|
|
1418766a1a | ||
|
|
752a064bb3 | ||
|
|
a4d771956a | ||
|
|
007a2bc835 | ||
|
|
6b576da5ef | ||
|
|
6bb13a564f | ||
|
|
bf482f6025 | ||
|
|
d49a8a3e64 | ||
|
|
95920af7b7 | ||
|
|
3d3271abe1 | ||
|
|
b713136a00 | ||
|
|
03ddc84384 | ||
|
|
580e1d5fc5 | ||
|
|
f42df2d846 | ||
|
|
ecc23a5a76 | ||
|
|
d63c6cd04e | ||
|
|
034819cd2d | ||
|
|
0f677fcaac | ||
|
|
efc9236fbc | ||
|
|
b9a99de158 | ||
|
|
81f95d3880 | ||
|
|
38ebb81536 | ||
|
|
939470df52 | ||
|
|
0239329f06 | ||
|
|
d5dffb70be | ||
|
|
4ffd45c126 | ||
|
|
ba6a8a43f7 | ||
|
|
5eddaeade6 | ||
|
|
fc76b4a258 | ||
|
|
b0cce363f1 | ||
|
|
10a4ec0b08 | ||
|
|
0688b74099 | ||
|
|
1130b7eade | ||
|
|
8f383ac531 | ||
|
|
7c9726da64 | ||
|
|
548fce69f8 | ||
|
|
b97acabb01 | ||
|
|
6c9a758648 | ||
|
|
e592c7e7b7 | ||
|
|
cebf4089cc | ||
|
|
099fda0d2b | ||
|
|
8b06f2c31d | ||
|
|
484e9dcdc3 | ||
|
|
9438064afc | ||
|
|
6ab4ac7f7f | ||
|
|
9eddbe88be | ||
|
|
e53e7cf961 | ||
|
|
90a08ad845 | ||
|
|
e58a5866bb | ||
|
|
4fc85409da | ||
|
|
47be86eb79 | ||
|
|
1712b99f79 | ||
|
|
89b1cc4f28 | ||
|
|
3a300a6a8f | ||
|
|
c4a3db4ac1 | ||
|
|
9554e87431 | ||
|
|
ea3e542450 | ||
|
|
05e066b2ff | ||
|
|
8df5c15db9 | ||
|
|
e1bbdd5e65 | ||
|
|
7f553c1276 | ||
|
|
b7850e9cbf | ||
|
|
50f3ba3189 | ||
|
|
014a15ba62 | ||
|
|
5b133233f7 | ||
|
|
c77a311a89 | ||
|
|
57cd11fffe | ||
|
|
fe9a3d9a10 | ||
|
|
625f56b494 | ||
|
|
0ebd5d3879 | ||
|
|
d52dfb002d | ||
|
|
1801023c68 | ||
|
|
a004fdffed | ||
|
|
c6ea7afb76 | ||
|
|
469d3ee177 | ||
|
|
8cfd2aacaf | ||
|
|
8e1335e372 | ||
|
|
8a10e545d4 |
173
.github/workflows/build.yml
vendored
Normal file
173
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
name: Build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
linux:
|
||||
|
||||
name: Linux
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
compiler: [gcc, clang]
|
||||
|
||||
env:
|
||||
CC: ${{ matrix.compiler }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install libbluetooth-dev libusb-1.0-0-dev
|
||||
- run: autoreconf --install --force
|
||||
- run: ./configure --prefix=/usr
|
||||
- run: make
|
||||
- run: make distcheck
|
||||
- name: Package artifacts
|
||||
run: |
|
||||
make install DESTDIR=$PWD/artifacts
|
||||
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ github.job }}-${{ matrix.compiler }}
|
||||
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
|
||||
|
||||
mac:
|
||||
|
||||
name: Mac
|
||||
|
||||
runs-on: macos-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
compiler: [gcc, clang]
|
||||
|
||||
env:
|
||||
CC: ${{ matrix.compiler }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install dependencies
|
||||
run: brew install autoconf automake libtool hidapi libusb
|
||||
- run: autoreconf --install --force
|
||||
- run: ./configure --prefix=/usr
|
||||
- run: make
|
||||
- run: make distcheck
|
||||
- name: Package artifacts
|
||||
run: |
|
||||
make install DESTDIR=$PWD/artifacts
|
||||
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ github.job }}-${{ matrix.compiler }}
|
||||
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
|
||||
|
||||
windows:
|
||||
|
||||
name: Windows
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arch: [i686, x86_64]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install gcc-mingw-w64 binutils-mingw-w64 mingw-w64-tools
|
||||
- name: Install libusb
|
||||
env:
|
||||
LIBUSB_VERSION: 1.0.26
|
||||
run: |
|
||||
wget -c https://github.com/libusb/libusb/archive/refs/tags/v${LIBUSB_VERSION}.tar.gz
|
||||
tar xzf v${LIBUSB_VERSION}.tar.gz
|
||||
pushd libusb-${LIBUSB_VERSION}
|
||||
autoreconf --install --force
|
||||
./configure --host=${{ matrix.arch }}-w64-mingw32 --prefix=/usr
|
||||
make
|
||||
make install DESTDIR=$PWD/../artifacts
|
||||
popd
|
||||
- name: Install hidapi
|
||||
env:
|
||||
HIDAPI_VERSION: 0.12.0
|
||||
run: |
|
||||
wget -c https://github.com/libusb/hidapi/archive/refs/tags/hidapi-${HIDAPI_VERSION}.tar.gz
|
||||
tar xzf hidapi-${HIDAPI_VERSION}.tar.gz
|
||||
pushd hidapi-hidapi-${HIDAPI_VERSION}
|
||||
autoreconf --install --force
|
||||
./configure --host=${{ matrix.arch }}-w64-mingw32 --prefix=/usr LDFLAGS='-static-libgcc'
|
||||
make
|
||||
make install DESTDIR=$PWD/../artifacts
|
||||
popd
|
||||
- run: autoreconf --install --force
|
||||
- run: ./configure --host=${{ matrix.arch }}-w64-mingw32 --prefix=/usr
|
||||
env:
|
||||
PKG_CONFIG_LIBDIR: ${{ github.workspace }}/artifacts/usr/lib/pkgconfig
|
||||
PKG_CONFIG_SYSROOT_DIR: ${{ github.workspace }}/artifacts
|
||||
PKG_CONFIG_ALLOW_SYSTEM_CFLAGS: 1
|
||||
PKG_CONFIG_ALLOW_SYSTEM_LIBS: 1
|
||||
- run: make
|
||||
- run: make distcheck
|
||||
- name: Package artifacts
|
||||
run: |
|
||||
make install DESTDIR=$PWD/artifacts
|
||||
tar -czf ${{ github.job }}-${{ matrix.arch }}.tar.gz -C artifacts usr
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ github.job }}-${{ matrix.arch }}
|
||||
path: ${{ github.job }}-${{ matrix.arch }}.tar.gz
|
||||
|
||||
# msvc:
|
||||
#
|
||||
# name: Visual Studio
|
||||
#
|
||||
# runs-on: windows-latest
|
||||
#
|
||||
# strategy:
|
||||
# fail-fast: false
|
||||
# matrix:
|
||||
# platform: [x86, x64]
|
||||
#
|
||||
# env:
|
||||
# CONFIGURATION: Release
|
||||
#
|
||||
# steps:
|
||||
# - uses: actions/checkout@v3
|
||||
# - uses: msys2/setup-msys2@v2
|
||||
# with:
|
||||
# install: autoconf automake libtool pkg-config make gcc
|
||||
# - run: |
|
||||
# autoreconf --install --force
|
||||
# ./configure --prefix=/usr
|
||||
# make -C src revision.h
|
||||
# shell: msys2 {0}
|
||||
# - uses: microsoft/setup-msbuild@v1
|
||||
# - run: msbuild -m -p:Platform=${{ matrix.platform }} -p:Configuration=${{ env.CONFIGURATION }} contrib/msvc/libdivecomputer.vcxproj
|
||||
# - uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: ${{ github.job }}-${{ matrix.platform }}
|
||||
# path: contrib/msvc/${{ matrix.platform }}/${{ env.CONFIGURATION }}/bin
|
||||
|
||||
android:
|
||||
|
||||
name: Android
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: |
|
||||
autoreconf --install --force
|
||||
./configure --prefix=/usr
|
||||
make -C src revision.h
|
||||
- run: $ANDROID_NDK/ndk-build -C contrib/android NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ github.job }}
|
||||
path: contrib/android/libs
|
||||
47
.github/workflows/release.yml
vendored
Normal file
47
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: 'v*'
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Version number
|
||||
id: version
|
||||
run: |
|
||||
VERSION="${GITHUB_REF/refs\/tags\/v/}"
|
||||
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build distribution tarball
|
||||
id: build
|
||||
run: |
|
||||
sudo apt-get install libbluetooth-dev libusb-1.0-0-dev
|
||||
autoreconf --install --force
|
||||
./configure
|
||||
make
|
||||
make distcheck
|
||||
|
||||
- name: Check tarball version number
|
||||
id: check
|
||||
run: |
|
||||
FILENAME="libdivecomputer-${{ steps.version.outputs.version }}.tar.gz"
|
||||
if [ ! -f "${FILENAME}" ]; then
|
||||
echo ::error ::Tarball \'${FILENAME}\' not found!
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Create Github release
|
||||
id: release
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
if [ "${VERSION}" != "${VERSION%%-*}" ]; then
|
||||
PRERELEASE="-p"
|
||||
fi
|
||||
gh release create ${PRERELEASE} "${{ github.ref }}" "libdivecomputer-${VERSION}.tar.gz"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@ -47,11 +47,10 @@ Makefile.in
|
||||
/m4/ltsugar.m4
|
||||
/m4/ltversion.m4
|
||||
|
||||
/msvc/Debug/
|
||||
/msvc/Release/
|
||||
/msvc/x64/
|
||||
/msvc/x86/
|
||||
/msvc/*.ncb
|
||||
/msvc/*.suo
|
||||
/msvc/*.vcproj.*.user
|
||||
|
||||
/src/libdivecomputer.exp
|
||||
/src/libdivecomputer.la
|
||||
|
||||
@ -16,4 +16,8 @@ pkgconfig_DATA = libdivecomputer.pc
|
||||
|
||||
EXTRA_DIST = \
|
||||
libdivecomputer.pc.in \
|
||||
msvc/libdivecomputer.vcproj
|
||||
contrib/README \
|
||||
contrib/android/Android.mk \
|
||||
contrib/msvc/libdivecomputer.vcxproj \
|
||||
contrib/msvc/libdivecomputer.vcxproj.filters \
|
||||
contrib/udev/libdivecomputer.rules
|
||||
|
||||
74
NEWS
74
NEWS
@ -1,3 +1,77 @@
|
||||
Version 0.8.0 (2023-05-11)
|
||||
==========================
|
||||
|
||||
The v0.8.0 release is mainly a bugfix release, and brings in support for a
|
||||
number of new devices. This release is fully backwards compatible with the
|
||||
previous one.
|
||||
|
||||
New features:
|
||||
|
||||
* Add support for new backends:
|
||||
- excursion: Deep Six Excursion, Crest CR-4, Genesis Centauri, Tusa TC1, Scorpena Alpha
|
||||
- screen: Seac Screen and Action
|
||||
- cosmiq: Deepblu Cosmiq+
|
||||
- s1: Oceans S1
|
||||
- freedom: Divesoft Freedom and Liberty
|
||||
* Add support for some new devices:
|
||||
- Aqualung: i200C
|
||||
- Cressi: Donatello, Michelangelo, Neon
|
||||
- Mares: Puck Pro +
|
||||
- Oceanic: Geo Air
|
||||
- Ratio: iX3M 2
|
||||
- Scubapro: G2 TEK
|
||||
- Shearwater: Petrel 3, Perdix 2
|
||||
- Sherwood: Amphos Air 2.0
|
||||
* Add support for parsing the decompression model
|
||||
* Add a public api to configure the depth calibration
|
||||
* Add a public api to configure the clock synchronization
|
||||
* Add a basic Android build system
|
||||
|
||||
Removed/changed features:
|
||||
|
||||
* Migrate to Visual Studio 2013 (or newer)
|
||||
* Move the Visual Studio project to the contrib directory
|
||||
|
||||
Version 0.7.0 (2021-05-07)
|
||||
==========================
|
||||
|
||||
The main highlight of the v0.7.0 release is the introduction of the new
|
||||
I/O interface. With this common interface, the dive computer backends
|
||||
can more easily use different I/O implementations at runtime, including
|
||||
an application defined one. This is needed to support Bluetooth Low
|
||||
Energy (BLE), for which there is no built-in implementation available.
|
||||
|
||||
Due to the fundamental changes to the I/O layer, this release is not
|
||||
backwards compatible.
|
||||
|
||||
New features:
|
||||
|
||||
* A new I/O interface
|
||||
* Add support for new backends:
|
||||
- goa: Cressi Goa and Cartesio
|
||||
- divecomputereu: Tecdiving DiveComputer.eu
|
||||
- extreme: McLean Extreme
|
||||
- lynx: Liquivision Xen, Xeo, Lynx and Kaon
|
||||
- sp2: Sporasub SP2
|
||||
* Add support for many new devices:
|
||||
- Aqualung: i100, i200C, i300C, i470TC, i550C, i770R
|
||||
- Heinrichs Weikamp: OSTC 2 TR
|
||||
- Mares: Genius, Horizon, Quad Air, Smart Air
|
||||
- Oceanic: Geo 4.0, Pro Plus 4, Pro Plus X, Veo 4.0
|
||||
- Ratio: iDive Color, iX3M GPS, iX3M 2021
|
||||
- Scubapro: A1, A2, Aladin H Matrix, G2 Console, G2 HUD
|
||||
- Seac: Guru, Jack
|
||||
- Shearwater: Peregrine, Teric
|
||||
- Sherwood: Amphos 2.0, Beacon, Sage, Wisdom 4
|
||||
- Suunto: D5, EON Steel Black
|
||||
- Tusa: Talis
|
||||
* Firmware upgrade support for the Ratio computers
|
||||
* Support for semi-closed circuit diving
|
||||
|
||||
Removed/changed features:
|
||||
|
||||
* Unify the Uwatec Smart, Meridian and G2 backends
|
||||
|
||||
Version 0.6.0 (2017-11-24)
|
||||
==========================
|
||||
|
||||
|
||||
97
configure.ac
97
configure.ac
@ -1,6 +1,6 @@
|
||||
# Versioning.
|
||||
m4_define([dc_version_major],[0])
|
||||
m4_define([dc_version_minor],[7])
|
||||
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]))
|
||||
@ -72,18 +72,21 @@ AM_CONDITIONAL([HAVE_MANDOC],[test -n "$MANDOC"])
|
||||
# Enable automake silent build rules.
|
||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
||||
|
||||
# Checks for native Windows.
|
||||
AC_MSG_CHECKING([for native Win32])
|
||||
# Checks for operating system.
|
||||
AC_MSG_CHECKING([for operating system])
|
||||
case "$host" in
|
||||
*-*-mingw*)
|
||||
os_win32=yes
|
||||
platform=windows
|
||||
;;
|
||||
*-*-darwin*)
|
||||
platform=mac
|
||||
;;
|
||||
*)
|
||||
os_win32=no
|
||||
platform=default
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT([$os_win32])
|
||||
AM_CONDITIONAL([OS_WIN32], [test "$os_win32" = "yes"])
|
||||
AC_MSG_RESULT([$platform])
|
||||
AM_CONDITIONAL([OS_WIN32], [test "$platform" = "windows"])
|
||||
|
||||
DEPENDENCIES=""
|
||||
|
||||
@ -100,16 +103,29 @@ AS_IF([test "x$with_libusb" != "xno"], [
|
||||
])
|
||||
])
|
||||
|
||||
# Checks for MTP support.
|
||||
AC_ARG_WITH([libmtp],
|
||||
[AS_HELP_STRING([--without-libmtp],
|
||||
[Build without the libmtp library])],
|
||||
[], [with_libmtp=auto])
|
||||
AS_IF([test "x$with_libmtp" != "xno"], [
|
||||
PKG_CHECK_MODULES([LIBMTP], [libmtp], [have_libmtp=yes], [have_libmtp=no])
|
||||
AS_IF([test "x$have_libmtp" = "xyes"], [
|
||||
AC_DEFINE([HAVE_LIBMTP], [1], [libmtp library])
|
||||
DEPENDENCIES="$DEPENDENCIES libmtp"
|
||||
])
|
||||
])
|
||||
|
||||
# Checks for HIDAPI support.
|
||||
AC_ARG_WITH([hidapi],
|
||||
[AS_HELP_STRING([--without-hidapi],
|
||||
[Build without the hidapi library])],
|
||||
[], [with_hidapi=auto])
|
||||
[], [with_hidapi=hidapi])
|
||||
AS_IF([test "x$with_hidapi" != "xno"], [
|
||||
PKG_CHECK_MODULES([HIDAPI], [hidapi], [have_hidapi=yes], [have_hidapi=no])
|
||||
PKG_CHECK_MODULES([HIDAPI], [$with_hidapi], [have_hidapi=yes], [have_hidapi=no])
|
||||
AS_IF([test "x$have_hidapi" = "xyes"], [
|
||||
AC_DEFINE([HAVE_HIDAPI], [1], [hidapi library])
|
||||
DEPENDENCIES="$DEPENDENCIES hidapi"
|
||||
DEPENDENCIES="$DEPENDENCIES $with_hidapi"
|
||||
])
|
||||
])
|
||||
|
||||
@ -154,7 +170,7 @@ AC_CHECK_HEADERS([sys/socket.h linux/types.h linux/irda.h], , , [
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS([linux/serial.h])
|
||||
AC_CHECK_HEADERS([IOKit/serial/ioss.h])
|
||||
AC_CHECK_HEADERS([getopt.h])
|
||||
AC_CHECK_HEADERS([unistd.h getopt.h])
|
||||
AC_CHECK_HEADERS([sys/param.h])
|
||||
AC_CHECK_HEADERS([pthread.h])
|
||||
AC_CHECK_HEADERS([mach/mach_time.h])
|
||||
@ -174,6 +190,7 @@ AC_CHECK_FUNCS([clock_gettime mach_absolute_time])
|
||||
AC_CHECK_FUNCS([getopt_long])
|
||||
|
||||
# Checks for supported compiler options.
|
||||
AX_APPEND_COMPILE_FLAGS([-Werror=unknown-warning-option],[ERROR_CFLAGS])
|
||||
AX_APPEND_COMPILE_FLAGS([ \
|
||||
-Wall \
|
||||
-Wshadow \
|
||||
@ -190,11 +207,13 @@ AX_APPEND_COMPILE_FLAGS([ \
|
||||
-Wno-unused-but-set-variable \
|
||||
-Wno-pointer-sign \
|
||||
-Wno-shadow \
|
||||
-Wenum-conversion \
|
||||
-Werror=enum-conversion \
|
||||
-fmacro-prefix-map='$(top_srcdir)/'= \
|
||||
])
|
||||
],,[$ERROR_CFLAGS])
|
||||
|
||||
# Windows specific compiler options.
|
||||
AS_IF([test "$os_win32" = "yes"], [
|
||||
AS_IF([test "$platform" = "windows"], [
|
||||
AX_APPEND_COMPILE_FLAGS([-Wno-pedantic-ms-format])
|
||||
])
|
||||
|
||||
@ -210,6 +229,25 @@ m4_ifset([dc_version_suffix],[
|
||||
AC_DEFINE(HAVE_VERSION_SUFFIX, [1], [Define if a version suffix is present.])
|
||||
])
|
||||
|
||||
# Supported transports
|
||||
transport_serial="yes"
|
||||
transport_usb="${have_libusb-no}"
|
||||
if test "$have_hidapi" = "yes"; then
|
||||
transport_usbhid="yes"
|
||||
elif test "$have_libusb" = "yes" && test "$platform" != "mac"; then
|
||||
transport_usbhid="yes"
|
||||
else
|
||||
transport_usbhid="no"
|
||||
fi
|
||||
if test "$platform" = "windows"; then
|
||||
transport_irda="$ac_cv_header_af_irda_h"
|
||||
transport_bluetooth="$ac_cv_header_ws2bth_h"
|
||||
else
|
||||
transport_irda="$ac_cv_header_linux_irda_h"
|
||||
transport_bluetooth="${have_bluez-no}"
|
||||
fi
|
||||
transport_ble="no"
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
libdivecomputer.pc
|
||||
Makefile
|
||||
@ -217,10 +255,41 @@ AC_CONFIG_FILES([
|
||||
include/libdivecomputer/Makefile
|
||||
include/libdivecomputer/version.h
|
||||
src/Makefile
|
||||
src/libdivecomputer.rc
|
||||
doc/Makefile
|
||||
doc/doxygen.cfg
|
||||
doc/man/Makefile
|
||||
examples/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
AC_MSG_NOTICE([
|
||||
$PACKAGE $VERSION
|
||||
===============
|
||||
|
||||
Compiler:
|
||||
|
||||
CC : $CC
|
||||
CFLAGS : $CFLAGS
|
||||
LDFLAGS : $LDFLAGS
|
||||
|
||||
Features:
|
||||
|
||||
Logging : $enable_logging
|
||||
Pseudo terminal : $enable_pty
|
||||
Example applications : $enable_examples
|
||||
Documentation : $enable_doc
|
||||
|
||||
Transports:
|
||||
|
||||
Serial : $transport_serial
|
||||
USB : $transport_usb
|
||||
USBHID : $transport_usbhid
|
||||
IrDA : $transport_irda
|
||||
Bluetooth : $transport_bluetooth
|
||||
BLE : $transport_ble
|
||||
|
||||
Building:
|
||||
|
||||
Type 'make' to compile $PACKAGE.
|
||||
|
||||
Type 'make install' to install $PACKAGE.
|
||||
])
|
||||
|
||||
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>
|
||||
17
contrib/msvc/libdivecomputer.vcxproj.filters
Normal file
17
contrib/msvc/libdivecomputer.vcxproj.filters
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@ -1,23 +1,35 @@
|
||||
# Atomic Aquatics Cobalt
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="0471", ATTR{idProduct}=="0888", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0471", ATTRS{idProduct}=="0888", GROUP="plugdev"
|
||||
|
||||
# Suunto EON Steel
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0030", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0030", GROUP="plugdev"
|
||||
|
||||
# Suunto EON Core
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0033", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0033", GROUP="plugdev"
|
||||
|
||||
# Suunto D5
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0035", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0035", GROUP="plugdev"
|
||||
|
||||
# Suunto EON Steel Black
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0036", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0036", GROUP="plugdev"
|
||||
|
||||
# Scubapro G2
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3201", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2e6c", ATTRS{idProduct}=="3201", GROUP="plugdev"
|
||||
|
||||
# Scubapro G2 Console
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3211", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2e6c", ATTRS{idProduct}=="3211", GROUP="plugdev"
|
||||
|
||||
# Scubapro G2 HUD
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="4201", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2e6c", ATTRS{idProduct}=="4201", GROUP="plugdev"
|
||||
|
||||
# Scubapro Aladin Square
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="c251", ATTR{idProduct}=="2006", GROUP="plugdev"
|
||||
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2006", GROUP="plugdev"
|
||||
|
||||
@ -32,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},
|
||||
@ -91,13 +92,17 @@ static const backend_table_t g_backends[] = {
|
||||
{"idive", DC_FAMILY_DIVESYSTEM_IDIVE, 0x03},
|
||||
{"cochran", DC_FAMILY_COCHRAN_COMMANDER, 0},
|
||||
{"divecomputereu", DC_FAMILY_TECDIVING_DIVECOMPUTEREU, 0},
|
||||
{"mclean", DC_FAMILY_MCLEAN_EXTREME, 0},
|
||||
{"extreme", DC_FAMILY_MCLEAN_EXTREME, 0},
|
||||
{"lynx", DC_FAMILY_LIQUIVISION_LYNX, 0},
|
||||
{"sp2", DC_FAMILY_SPORASUB_SP2, 0},
|
||||
{"excursion", DC_FAMILY_DEEPSIX_EXCURSION, 0},
|
||||
{"screen", DC_FAMILY_SEAC_SCREEN, 0},
|
||||
{"cosmiq", DC_FAMILY_DEEPBLU_COSMIQ, 0},
|
||||
{"s1", DC_FAMILY_OCEANS_S1, 0},
|
||||
{"freedom", DC_FAMILY_DIVESOFT_FREEDOM, 19},
|
||||
|
||||
// Not merged upstream yet
|
||||
{"descentmk1", DC_FAMILY_GARMIN, 0},
|
||||
{"cosmiq", DC_FAMILY_DEEPBLU, 0},
|
||||
{"oceans", DC_FAMILY_OCEANS_S1, 0},
|
||||
};
|
||||
|
||||
static const transport_table_t g_transports[] = {
|
||||
|
||||
@ -24,10 +24,12 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
@ -48,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 ""
|
||||
@ -240,7 +242,8 @@ main (int argc, char *argv[])
|
||||
}
|
||||
|
||||
// Translate the help option into a command.
|
||||
char *argv_help[] = {(char *) "help", NULL, NULL};
|
||||
char helpcmd[] = "help";
|
||||
char *argv_help[] = {helpcmd, NULL, NULL};
|
||||
if (help || argv[0] == NULL) {
|
||||
if (argv[0]) {
|
||||
argv_help[1] = argv[0];
|
||||
|
||||
@ -24,9 +24,11 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
@ -78,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);
|
||||
|
||||
@ -24,9 +24,11 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
@ -24,8 +24,10 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
@ -92,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);
|
||||
|
||||
@ -24,8 +24,10 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
@ -24,8 +24,10 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
@ -24,9 +24,11 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
@ -52,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;
|
||||
}
|
||||
|
||||
@ -152,7 +154,7 @@ dctool_parse_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < argc; ++i) {
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
// Read the input file.
|
||||
buffer = dctool_file_read (argv[i]);
|
||||
if (buffer == NULL) {
|
||||
|
||||
@ -24,8 +24,10 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
@ -24,8 +24,10 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
@ -158,7 +160,7 @@ dctool_scan_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t
|
||||
|
||||
// Show help message.
|
||||
if (help) {
|
||||
dctool_command_showhelp (&dctool_list);
|
||||
dctool_command_showhelp (&dctool_scan);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@ -24,8 +24,10 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
@ -24,8 +24,10 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
@ -24,8 +24,10 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#endif
|
||||
|
||||
@ -80,7 +80,7 @@ mktemplate_datetime (char *buffer, size_t size, dc_parser_t *parser)
|
||||
n = snprintf (buffer, size, "%04i%02i%02iT%02i%02i%02i",
|
||||
datetime.year, datetime.month, datetime.day,
|
||||
datetime.hour, datetime.minute, datetime.second);
|
||||
if (n < 0 || n >= size)
|
||||
if (n < 0 || (size_t) n >= size)
|
||||
return -1;
|
||||
|
||||
return n;
|
||||
@ -92,7 +92,7 @@ mktemplate_number (char *buffer, size_t size, unsigned int number)
|
||||
int n = 0;
|
||||
|
||||
n = snprintf (buffer, size, "%04u", number);
|
||||
if (n < 0 || n >= size)
|
||||
if (n < 0 || (size_t) n >= size)
|
||||
return -1;
|
||||
|
||||
return n;
|
||||
|
||||
@ -90,7 +90,7 @@ convert_volume (double value, dctool_units_t units)
|
||||
}
|
||||
|
||||
static void
|
||||
sample_cb (dc_sample_type_t type, 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;
|
||||
@ -238,7 +254,7 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
||||
fprintf (output->ostream, "<datetime>%04i-%02i-%02i %02i:%02i:%02i %+03i:%02i</datetime>\n",
|
||||
dt.year, dt.month, dt.day,
|
||||
dt.hour, dt.minute, dt.second,
|
||||
dt.timezone / 3600, (dt.timezone % 3600) / 60);
|
||||
dt.timezone / 3600, (abs(dt.timezone) % 3600) / 60);
|
||||
}
|
||||
|
||||
// Parse the divetime.
|
||||
@ -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"
|
||||
@ -386,6 +416,30 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
||||
names[divemode]);
|
||||
}
|
||||
|
||||
// Parse the deco model.
|
||||
message ("Parsing the deco model.\n");
|
||||
dc_decomodel_t decomodel = {DC_DECOMODEL_NONE};
|
||||
status = dc_parser_get_field (parser, DC_FIELD_DECOMODEL, 0, &decomodel);
|
||||
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
|
||||
ERROR ("Error parsing the deco model.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (status != DC_STATUS_UNSUPPORTED) {
|
||||
const char *names[] = {"none", "buhlmann", "vpm", "rgbm", "dciem"};
|
||||
fprintf (output->ostream, "<decomodel>%s</decomodel>\n",
|
||||
names[decomodel.type]);
|
||||
if (decomodel.type == DC_DECOMODEL_BUHLMANN &&
|
||||
(decomodel.params.gf.low != 0 || decomodel.params.gf.high != 0)) {
|
||||
fprintf (output->ostream, "<gf>%u/%u</gf>\n",
|
||||
decomodel.params.gf.low, decomodel.params.gf.high);
|
||||
}
|
||||
if (decomodel.conservatism) {
|
||||
fprintf (output->ostream, "<conservatism>%d</conservatism>\n",
|
||||
decomodel.conservatism);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the salinity.
|
||||
message ("Parsing the salinity.\n");
|
||||
dc_salinity_t salinity = {DC_WATER_FRESH, 0.0};
|
||||
@ -396,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.
|
||||
|
||||
@ -26,6 +26,12 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#define strcasecmp _stricmp
|
||||
#define strncasecmp _strnicmp
|
||||
#endif
|
||||
|
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
||||
#define FUNCTION __func__
|
||||
#else
|
||||
|
||||
@ -36,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 */
|
||||
|
||||
@ -51,6 +51,9 @@ dc_buffer_append (dc_buffer_t *buffer, const unsigned char data[], size_t size);
|
||||
int
|
||||
dc_buffer_prepend (dc_buffer_t *buffer, const unsigned char data[], size_t size);
|
||||
|
||||
int
|
||||
dc_buffer_insert (dc_buffer_t *buffer, size_t offset, const unsigned char data[], size_t size);
|
||||
|
||||
int
|
||||
dc_buffer_slice (dc_buffer_t *buffer, size_t offset, size_t size);
|
||||
|
||||
|
||||
@ -78,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,
|
||||
@ -112,14 +113,22 @@ typedef enum dc_family_t {
|
||||
DC_FAMILY_MCLEAN_EXTREME = (16 << 16),
|
||||
/* Liquivision */
|
||||
DC_FAMILY_LIQUIVISION_LYNX = (17 << 16),
|
||||
/* Sporasub */
|
||||
DC_FAMILY_SPORASUB_SP2 = (18 << 16),
|
||||
/* Deep Six */
|
||||
DC_FAMILY_DEEPSIX_EXCURSION = (19 << 16),
|
||||
/* Seac Screen */
|
||||
DC_FAMILY_SEAC_SCREEN = (20 << 16),
|
||||
/* Deepblu Cosmiq */
|
||||
DC_FAMILY_DEEPBLU_COSMIQ = (21 << 16),
|
||||
/* Oceans S1 */
|
||||
DC_FAMILY_OCEANS_S1 = (22 << 16),
|
||||
/* Divesoft Freedom */
|
||||
DC_FAMILY_DIVESOFT_FREEDOM = (23 << 16),
|
||||
|
||||
// Not merged upstream yet
|
||||
/* Garmin */
|
||||
DC_FAMILY_GARMIN = (100 << 16),
|
||||
/* Deepblu */
|
||||
DC_FAMILY_DEEPBLU = (101 << 16),
|
||||
/* Oceans S1 */
|
||||
DC_FAMILY_OCEANS_S1 = (102 << 16),
|
||||
} dc_family_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -22,11 +22,13 @@
|
||||
#ifndef DC_DATETIME_H
|
||||
#define DC_DATETIME_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define DC_TIMEZONE_NONE 0x80000000
|
||||
#define DC_TIMEZONE_NONE INT_MIN
|
||||
|
||||
#if defined (_WIN32) && !defined (__GNUC__)
|
||||
typedef __int64 dc_ticks_t;
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -67,6 +67,7 @@ typedef enum dc_field_type_t {
|
||||
DC_FIELD_TANK_COUNT,
|
||||
DC_FIELD_TANK,
|
||||
DC_FIELD_DIVEMODE,
|
||||
DC_FIELD_DECOMODEL,
|
||||
DC_FIELD_STRING,
|
||||
} dc_field_type_t;
|
||||
|
||||
@ -172,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
|
||||
@ -214,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 */
|
||||
@ -221,15 +234,53 @@ typedef struct dc_tank_t {
|
||||
double workpressure; /* Work pressure (bar) */
|
||||
double beginpressure; /* Begin pressure (bar) */
|
||||
double endpressure; /* End pressure (bar) */
|
||||
dc_tank_usage_t usage;
|
||||
} dc_tank_t;
|
||||
|
||||
typedef enum dc_decomodel_type_t {
|
||||
DC_DECOMODEL_NONE,
|
||||
DC_DECOMODEL_BUHLMANN,
|
||||
DC_DECOMODEL_VPM,
|
||||
DC_DECOMODEL_RGBM,
|
||||
DC_DECOMODEL_DCIEM,
|
||||
} dc_decomodel_type_t;
|
||||
|
||||
/*
|
||||
* Decompression model
|
||||
*
|
||||
* The type field contains the decompression algorithm.
|
||||
*
|
||||
* The (optional) conservatism field contains the personal adjustment
|
||||
* setting of the algorithm. The exact interpretation depends on the
|
||||
* dive computer, but the default value (zero) will typically correspond
|
||||
* to the neutral setting, while a positive value is more conservative
|
||||
* and a negative value more aggressive.
|
||||
*
|
||||
* The (optional) params field contains the parameters of the algorithm:
|
||||
*
|
||||
* DC_DECOMODEL_BUHLMANN: The Gradient Factor (GF) parameters low and
|
||||
* high. For a pure Buhlmann algorithm (e.g. without GF enabled), both
|
||||
* values are 100. If GF are enabled, but the actual parameter values
|
||||
* are not available from the dive computer, both values are zero.
|
||||
*/
|
||||
typedef struct dc_decomodel_t {
|
||||
dc_decomodel_type_t type;
|
||||
int conservatism;
|
||||
union {
|
||||
struct {
|
||||
unsigned int high;
|
||||
unsigned int low;
|
||||
} gf;
|
||||
} params;
|
||||
} dc_decomodel_t;
|
||||
|
||||
typedef struct dc_field_string_t {
|
||||
const char *desc;
|
||||
const char *value;
|
||||
} dc_field_string_t;
|
||||
|
||||
typedef union dc_sample_value_t {
|
||||
unsigned int time;
|
||||
unsigned int time; /* Milliseconds */
|
||||
double depth;
|
||||
struct {
|
||||
unsigned int tank;
|
||||
@ -252,31 +303,41 @@ 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);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_set_data (dc_parser_t *parser, const unsigned char *data, unsigned int size);
|
||||
dc_parser_set_clock (dc_parser_t *parser, unsigned int devtime, dc_ticks_t systime);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_set_atmospheric (dc_parser_t *parser, double atmospheric);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_set_density (dc_parser_t *parser, double density);
|
||||
|
||||
dc_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,995 +0,0 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="libdivecomputer"
|
||||
ProjectGUID="{CEA7215A-D6B5-4840-8086-3C854F371997}"
|
||||
RootNamespace="libdivecomputer"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="196613"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_AF_IRDA_H;HAVE_WS2BTH_H"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
CompileAs="2"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="ws2_32.lib"
|
||||
LinkIncremental="2"
|
||||
ModuleDefinitionFile="$(OutDir)/libdivecomputer.def"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
AdditionalIncludeDirectories="..\include"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBDIVECOMPUTER_EXPORTS;ENABLE_LOGGING;HAVE_AF_IRDA_H;HAVE_WS2BTH_H"
|
||||
RuntimeLibrary="2"
|
||||
EnableFunctionLevelLinking="true"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
CompileAs="2"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="ws2_32.lib"
|
||||
LinkIncremental="1"
|
||||
ModuleDefinitionFile="$(OutDir)/libdivecomputer.def"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\src\aes.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\array.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\atomics_cobalt.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\atomics_cobalt_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\bluetooth.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\buffer.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\checksum.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\citizen_aqualand.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\citizen_aqualand_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cochran_commander.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cochran_commander_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\common.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\context.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_edy.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_edy_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_goa.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_goa_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_leonardo.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_leonardo_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\custom.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\datetime.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\descriptor.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\device.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\diverite_nitekq.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\diverite_nitekq_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\divesystem_idive.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\divesystem_idive_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hw_frog.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hw_ostc.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hw_ostc3.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hw_ostc_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ihex.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\iostream.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\irda.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\iterator.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\liquivision_lynx.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\liquivision_lynx_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_common.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_darwin.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_darwin_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_iconhd.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_iconhd_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_nemo.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_nemo_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_puck.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mclean_extreme.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mclean_extreme_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_atom2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_atom2_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_common.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_veo250.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_veo250_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_vtpro.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_vtpro_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\rbstream.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensus.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensus_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensuspro.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensuspro_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensusultra.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensusultra_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ringbuffer.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\serial_win32.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\shearwater_common.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\shearwater_petrel.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\shearwater_predator.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\shearwater_predator_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\socket.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_common.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_common2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_d9.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_d9_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_eon.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_eon_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_eonsteel.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_eonsteel_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_solution.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_solution_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_vyper.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_vyper2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_vyper_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\tecdiving_divecomputereu.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\tecdiving_divecomputereu_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\garmin.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\garmin_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\deepblu.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\deepblu_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mclean_extreme.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mclean_extreme_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceans_s1.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceans_s1_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\field-cache.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\timer.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\usb.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\usbhid.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_aladin.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_memomouse.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_memomouse_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_smart.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_smart_parser.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\version.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\zeagle_n2ition3.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\src\aes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\array.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\atomics_cobalt.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\atomics_cobalt.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\bluetooth.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\buffer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\checksum.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\citizen_aqualand.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cochran_commander.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\common-private.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\context-private.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\context.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_edy.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_goa.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\cressi_leonardo.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\custom.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\datetime.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\descriptor.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\device-private.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\device.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\diverite_nitekq.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\divesystem_idive.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\hw_frog.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hw_frog.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\hw_ostc.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hw_ostc.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\hw_ostc3.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\hw_ostc3.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ihex.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\iostream-private.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\iostream.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\irda.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\iterator-private.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\iterator.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\liquivision_lynx.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_common.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_darwin.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_iconhd.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_nemo.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mares_puck.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mclean_extreme.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_atom2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\oceanic_atom2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_common.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_veo250.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\oceanic_veo250.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceanic_vtpro.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\oceanic_vtpro.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\parser-private.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\parser.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\platform.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\rbstream.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensus.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\reefnet_sensus.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensuspro.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\reefnet_sensuspro.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\reefnet_sensusultra.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\reefnet_sensusultra.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\revision.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\ringbuffer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\serial.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\shearwater_common.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\shearwater_petrel.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\shearwater_predator.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\socket.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_common.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_common2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\suunto_d9.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_d9.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\suunto_eon.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_eon.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_eonsteel.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_solution.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_vyper.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\suunto_vyper2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\suunto_vyper2.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\tecdiving_divecomputereu.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\garmin.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\deepblu.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\mclean_extreme.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\oceans_s1.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\timer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\units.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\usb.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\usbhid.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_aladin.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_memomouse.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\uwatec_smart.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\include\libdivecomputer\version.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\zeagle_n2ition3.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\src\libdivecomputer.rc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\libdivecomputer.symbols"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="echo EXPORTS > "$(OutDir)/libdivecomputer.def" && type "$(InputPath)" >> "$(OutDir)/libdivecomputer.def""
|
||||
Outputs="$(OutDir)/libdivecomputer.def"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
CommandLine="echo EXPORTS > "$(OutDir)/libdivecomputer.def" && type "$(InputPath)" >> "$(OutDir)/libdivecomputer.def""
|
||||
Outputs="$(OutDir)/libdivecomputer.def"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@ -1,9 +1,9 @@
|
||||
AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
AM_CFLAGS = $(LIBUSB_CFLAGS) $(HIDAPI_CFLAGS) $(BLUEZ_CFLAGS)
|
||||
AM_CFLAGS = $(LIBUSB_CFLAGS) $(LIBMTP_CFLAGS) $(HIDAPI_CFLAGS) $(BLUEZ_CFLAGS)
|
||||
|
||||
lib_LTLIBRARIES = libdivecomputer.la
|
||||
|
||||
libdivecomputer_la_LIBADD = $(LIBUSB_LIBS) $(HIDAPI_LIBS) $(BLUEZ_LIBS) -lm
|
||||
libdivecomputer_la_LIBADD = $(LIBUSB_LIBS) $(LIBMTP_LIBS) $(HIDAPI_LIBS) $(BLUEZ_LIBS) -lm
|
||||
libdivecomputer_la_LDFLAGS = \
|
||||
-version-info $(DC_VERSION_LIBTOOL) \
|
||||
-no-undefined \
|
||||
@ -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 \
|
||||
@ -64,7 +65,7 @@ libdivecomputer_la_SOURCES = \
|
||||
diverite_nitekq.h diverite_nitekq.c diverite_nitekq_parser.c \
|
||||
citizen_aqualand.h citizen_aqualand.c citizen_aqualand_parser.c \
|
||||
divesystem_idive.h divesystem_idive.c divesystem_idive_parser.c \
|
||||
platform.h \
|
||||
platform.h platform.c \
|
||||
ringbuffer.h ringbuffer.c \
|
||||
rbstream.h rbstream.c \
|
||||
checksum.h checksum.c \
|
||||
@ -74,6 +75,15 @@ libdivecomputer_la_SOURCES = \
|
||||
tecdiving_divecomputereu.h tecdiving_divecomputereu.c tecdiving_divecomputereu_parser.c \
|
||||
mclean_extreme.h mclean_extreme.c mclean_extreme_parser.c \
|
||||
liquivision_lynx.h liquivision_lynx.c liquivision_lynx_parser.c \
|
||||
sporasub_sp2.h sporasub_sp2.c sporasub_sp2_parser.c \
|
||||
deepsix_excursion.h deepsix_excursion.c deepsix_excursion_parser.c \
|
||||
seac_screen.h seac_screen.c seac_screen_parser.c \
|
||||
deepblu_cosmiq.h deepblu_cosmiq.c deepblu_cosmiq_parser.c \
|
||||
oceans_s1_common.h oceans_s1_common.c \
|
||||
oceans_s1.h oceans_s1.c oceans_s1_parser.c \
|
||||
divesoft_freedom.h divesoft_freedom.c divesoft_freedom_parser.c \
|
||||
hdlc.h hdlc.c \
|
||||
packet.h packet.c \
|
||||
socket.h socket.c \
|
||||
irda.c \
|
||||
usb.c \
|
||||
@ -85,9 +95,7 @@ libdivecomputer_la_SOURCES = \
|
||||
libdivecomputer_la_SOURCES += \
|
||||
usb_storage.c \
|
||||
field-cache.h field-cache.c \
|
||||
garmin.h garmin.c garmin_parser.c \
|
||||
deepblu.h deepblu.c deepblu_parser.c \
|
||||
oceans_s1.h oceans_s1.c oceans_s1_parser.c
|
||||
garmin.h garmin.c garmin_parser.c
|
||||
|
||||
if OS_WIN32
|
||||
libdivecomputer_la_SOURCES += serial_win32.c
|
||||
@ -105,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
|
||||
|
||||
|
||||
@ -98,7 +98,7 @@ typedef struct aes_state_t {
|
||||
|
||||
#if defined(CBC) && CBC
|
||||
// Initial Vector used only for CBC mode
|
||||
uint8_t* Iv;
|
||||
const uint8_t* Iv;
|
||||
#endif
|
||||
} aes_state_t;
|
||||
|
||||
@ -542,7 +542,7 @@ void AES128_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length,
|
||||
|
||||
if(iv != 0)
|
||||
{
|
||||
state.Iv = (uint8_t*)iv;
|
||||
state.Iv = iv;
|
||||
}
|
||||
|
||||
for(i = 0; i < length; i += KEYLEN)
|
||||
@ -584,7 +584,7 @@ void AES128_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length,
|
||||
// If iv is passed as 0, we continue to encrypt without re-setting the Iv
|
||||
if(iv != 0)
|
||||
{
|
||||
state.Iv = (uint8_t*)iv;
|
||||
state.Iv = iv;
|
||||
}
|
||||
|
||||
for(i = 0; i < length; i += KEYLEN)
|
||||
|
||||
187
src/array.c
187
src/array.c
@ -160,6 +160,30 @@ array_convert_str2num (const unsigned char data[], unsigned int size)
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
array_convert_bin2dec (const unsigned char data[], unsigned int size)
|
||||
{
|
||||
unsigned int value = 0;
|
||||
for (unsigned int i = 0; i < size; ++i) {
|
||||
value *= 100;
|
||||
value += data[i];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
array_convert_bcd2dec (const unsigned char data[], unsigned int size)
|
||||
{
|
||||
unsigned int value = 0;
|
||||
for (unsigned int i = 0; i < size; ++i) {
|
||||
value *= 100;
|
||||
value += bcd2dec(data[i]);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
array_uint_be (const unsigned char data[], unsigned int n)
|
||||
{
|
||||
@ -184,6 +208,32 @@ array_uint_le (const unsigned char data[], unsigned int n)
|
||||
return value;
|
||||
}
|
||||
|
||||
unsigned long long
|
||||
array_uint64_be (const unsigned char data[])
|
||||
{
|
||||
return ((unsigned long long) data[0] << 56) |
|
||||
((unsigned long long) data[1] << 48) |
|
||||
((unsigned long long) data[2] << 40) |
|
||||
((unsigned long long) data[3] << 32) |
|
||||
((unsigned long long) data[4] << 24) |
|
||||
((unsigned long long) data[5] << 16) |
|
||||
((unsigned long long) data[6] << 8) |
|
||||
((unsigned long long) data[7] << 0);
|
||||
}
|
||||
|
||||
unsigned long long
|
||||
array_uint64_le (const unsigned char data[])
|
||||
{
|
||||
return ((unsigned long long) data[0] << 0) |
|
||||
((unsigned long long) data[1] << 8) |
|
||||
((unsigned long long) data[2] << 16) |
|
||||
((unsigned long long) data[3] << 24) |
|
||||
((unsigned long long) data[4] << 32) |
|
||||
((unsigned long long) data[5] << 40) |
|
||||
((unsigned long long) data[6] << 48) |
|
||||
((unsigned long long) data[7] << 56);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
array_uint32_be (const unsigned char data[])
|
||||
{
|
||||
@ -213,17 +263,6 @@ array_uint32_word_be (const unsigned char data[])
|
||||
((unsigned int) data[3] << 16);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
array_uint32_le_set (unsigned char data[], const unsigned int input)
|
||||
{
|
||||
data[0] = input & 0xFF;
|
||||
data[1] = (input >> 8) & 0xFF;
|
||||
data[2] = (input >> 16) & 0xFF;
|
||||
data[3] = (input >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
array_uint24_be (const unsigned char data[])
|
||||
{
|
||||
@ -232,16 +271,6 @@ array_uint24_be (const unsigned char data[])
|
||||
((unsigned int) data[2] << 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
array_uint24_be_set (unsigned char data[], const unsigned int input)
|
||||
{
|
||||
data[0] = (input >> 16) & 0xFF;
|
||||
data[1] = (input >> 8) & 0xFF;
|
||||
data[2] = input & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
array_uint24_le (const unsigned char data[])
|
||||
{
|
||||
@ -265,8 +294,124 @@ array_uint16_le (const unsigned char data[])
|
||||
((unsigned int) data[1] << 8);
|
||||
}
|
||||
|
||||
void
|
||||
array_uint64_be_set (unsigned char data[], const unsigned long long input)
|
||||
{
|
||||
data[0] = (input >> 56) & 0xFF;
|
||||
data[1] = (input >> 48) & 0xFF;
|
||||
data[2] = (input >> 40) & 0xFF;
|
||||
data[3] = (input >> 32) & 0xFF;
|
||||
data[4] = (input >> 24) & 0xFF;
|
||||
data[5] = (input >> 16) & 0xFF;
|
||||
data[6] = (input >> 8) & 0xFF;
|
||||
data[7] = (input ) & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
array_uint64_le_set (unsigned char data[], const unsigned long long input)
|
||||
{
|
||||
data[0] = (input ) & 0xFF;
|
||||
data[1] = (input >> 8) & 0xFF;
|
||||
data[2] = (input >> 16) & 0xFF;
|
||||
data[3] = (input >> 24) & 0xFF;
|
||||
data[4] = (input >> 32) & 0xFF;
|
||||
data[5] = (input >> 40) & 0xFF;
|
||||
data[6] = (input >> 48) & 0xFF;
|
||||
data[7] = (input >> 56) & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
array_uint32_be_set (unsigned char data[], const unsigned int input)
|
||||
{
|
||||
data[0] = (input >> 24) & 0xFF;
|
||||
data[1] = (input >> 16) & 0xFF;
|
||||
data[2] = (input >> 8) & 0xFF;
|
||||
data[3] = (input ) & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
array_uint32_le_set (unsigned char data[], const unsigned int input)
|
||||
{
|
||||
data[0] = (input ) & 0xFF;
|
||||
data[1] = (input >> 8) & 0xFF;
|
||||
data[2] = (input >> 16) & 0xFF;
|
||||
data[3] = (input >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
array_uint24_be_set (unsigned char data[], const unsigned int input)
|
||||
{
|
||||
data[0] = (input >> 16) & 0xFF;
|
||||
data[1] = (input >> 8) & 0xFF;
|
||||
data[2] = (input ) & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
array_uint24_le_set (unsigned char data[], const unsigned int input)
|
||||
{
|
||||
data[0] = (input ) & 0xFF;
|
||||
data[1] = (input >> 8) & 0xFF;
|
||||
data[2] = (input >> 16) & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
array_uint16_be_set (unsigned char data[], const unsigned short input)
|
||||
{
|
||||
data[0] = (input >> 8) & 0xFF;
|
||||
data[1] = (input ) & 0xFF;
|
||||
}
|
||||
|
||||
void
|
||||
array_uint16_le_set (unsigned char data[], const unsigned short input)
|
||||
{
|
||||
data[0] = (input ) & 0xFF;
|
||||
data[1] = (input >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
unsigned char
|
||||
bcd2dec (unsigned char value)
|
||||
{
|
||||
return ((value >> 4) & 0x0f) * 10 + (value & 0x0f);
|
||||
}
|
||||
|
||||
unsigned char
|
||||
dec2bcd (unsigned char value)
|
||||
{
|
||||
if (value >= 100)
|
||||
return 0;
|
||||
|
||||
unsigned char hi = value / 10;
|
||||
unsigned char lo = value % 10;
|
||||
return (hi << 4) | lo;
|
||||
}
|
||||
|
||||
/*
|
||||
* When turning a two's-complement number with a certain number
|
||||
* of bits into one with more bits, the sign bit must be repeated
|
||||
* in all the extra bits.
|
||||
*/
|
||||
unsigned int
|
||||
signextend (unsigned int value, unsigned int nbits)
|
||||
{
|
||||
if (nbits <= 0 || nbits > 32)
|
||||
return 0;
|
||||
|
||||
unsigned int signbit = 1U << (nbits - 1);
|
||||
unsigned int mask = signbit - 1;
|
||||
|
||||
if ((value & signbit) == signbit)
|
||||
return value | ~mask;
|
||||
else
|
||||
return value & mask;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
popcount (unsigned int value)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
while (value) {
|
||||
value &= value - 1;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
53
src/array.h
53
src/array.h
@ -22,6 +22,8 @@
|
||||
#ifndef ARRAY_H
|
||||
#define ARRAY_H
|
||||
|
||||
#define C_ARRAY_SIZE(a) (sizeof (a) / sizeof *(a))
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
@ -52,12 +54,24 @@ array_convert_hex2bin (const unsigned char input[], unsigned int isize, unsigned
|
||||
unsigned int
|
||||
array_convert_str2num (const unsigned char data[], unsigned int size);
|
||||
|
||||
unsigned int
|
||||
array_convert_bin2dec (const unsigned char data[], unsigned int size);
|
||||
|
||||
unsigned int
|
||||
array_convert_bcd2dec (const unsigned char data[], unsigned int size);
|
||||
|
||||
unsigned int
|
||||
array_uint_be (const unsigned char data[], unsigned int n);
|
||||
|
||||
unsigned int
|
||||
array_uint_le (const unsigned char data[], unsigned int n);
|
||||
|
||||
unsigned long long
|
||||
array_uint64_be (const unsigned char data[]);
|
||||
|
||||
unsigned long long
|
||||
array_uint64_le (const unsigned char data[]);
|
||||
|
||||
unsigned int
|
||||
array_uint32_be (const unsigned char data[]);
|
||||
|
||||
@ -67,15 +81,9 @@ array_uint32_le (const unsigned char data[]);
|
||||
unsigned int
|
||||
array_uint32_word_be (const unsigned char data[]);
|
||||
|
||||
void
|
||||
array_uint32_le_set (unsigned char data[], const unsigned int input);
|
||||
|
||||
unsigned int
|
||||
array_uint24_be (const unsigned char data[]);
|
||||
|
||||
void
|
||||
array_uint24_be_set (unsigned char data[], const unsigned int input);
|
||||
|
||||
unsigned int
|
||||
array_uint24_le (const unsigned char data[]);
|
||||
|
||||
@ -85,9 +93,42 @@ array_uint16_be (const unsigned char data[]);
|
||||
unsigned short
|
||||
array_uint16_le (const unsigned char data[]);
|
||||
|
||||
void
|
||||
array_uint64_be_set (unsigned char data[], const unsigned long long input);
|
||||
|
||||
void
|
||||
array_uint64_le_set (unsigned char data[], const unsigned long long input);
|
||||
|
||||
void
|
||||
array_uint32_be_set (unsigned char data[], const unsigned int input);
|
||||
|
||||
void
|
||||
array_uint32_le_set (unsigned char data[], const unsigned int input);
|
||||
|
||||
void
|
||||
array_uint24_be_set (unsigned char data[], const unsigned int input);
|
||||
|
||||
void
|
||||
array_uint24_le_set (unsigned char data[], const unsigned int input);
|
||||
|
||||
void
|
||||
array_uint16_be_set (unsigned char data[], const unsigned short input);
|
||||
|
||||
void
|
||||
array_uint16_le_set (unsigned char data[], const unsigned short input);
|
||||
|
||||
unsigned char
|
||||
bcd2dec (unsigned char value);
|
||||
|
||||
unsigned char
|
||||
dec2bcd (unsigned char value);
|
||||
|
||||
unsigned int
|
||||
signextend (unsigned int value, unsigned int nbits);
|
||||
|
||||
unsigned int
|
||||
popcount (unsigned int value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -41,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
|
||||
@ -210,6 +212,15 @@ atomics_cobalt_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init,
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Adjust the maximum value to take into account the two byte checksum and
|
||||
// the 8 byte serial number. Those extra bytes are not stored inside the
|
||||
// dive header and are added dynamically during the data transfer. Since we
|
||||
// don't know the total number of dives in advance, we can't calculate the
|
||||
// total number of extra bytes and adjust the maximum on the fly.
|
||||
if (progress) {
|
||||
progress->maximum += 2 + 8;
|
||||
}
|
||||
|
||||
// Send the command to the dive computer.
|
||||
unsigned char bRequest = 0;
|
||||
if (device->simulation)
|
||||
@ -338,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;
|
||||
@ -348,12 +365,6 @@ atomics_cobalt_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Adjust the maximum value to take into account the two checksum bytes
|
||||
// for the next dive. Since we don't know the total number of dives in
|
||||
// advance, we can't calculate the total number of checksum bytes and
|
||||
// adjust the maximum on the fly.
|
||||
progress.maximum += 2;
|
||||
|
||||
ndives++;
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
atomics_cobalt_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
atomics_cobalt_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -46,11 +46,10 @@ typedef struct atomics_cobalt_parser_t atomics_cobalt_parser_t;
|
||||
struct atomics_cobalt_parser_t {
|
||||
dc_parser_t base;
|
||||
// Depth calibration.
|
||||
double atmospheric;
|
||||
double hydrostatic;
|
||||
};
|
||||
|
||||
static dc_status_t atomics_cobalt_parser_set_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);
|
||||
static dc_status_t atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -58,7 +57,9 @@ 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 */
|
||||
atomics_cobalt_parser_get_datetime, /* datetime */
|
||||
atomics_cobalt_parser_get_field, /* fields */
|
||||
atomics_cobalt_parser_samples_foreach, /* samples_foreach */
|
||||
@ -67,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;
|
||||
|
||||
@ -75,15 +76,14 @@ 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;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
parser->atmospheric = 0.0;
|
||||
parser->hydrostatic = 1025.0 * GRAVITY;
|
||||
parser->hydrostatic = DEF_DENSITY_SALT * GRAVITY;
|
||||
|
||||
*out = (dc_parser_t*) parser;
|
||||
|
||||
@ -92,22 +92,11 @@ 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)
|
||||
atomics_cobalt_parser_set_density (dc_parser_t *abstract, double density)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
atomics_cobalt_parser_t *parser = (atomics_cobalt_parser_t *) abstract;
|
||||
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_parser_set_calibration (dc_parser_t *abstract, double atmospheric, double hydrostatic)
|
||||
{
|
||||
atomics_cobalt_parser_t *parser = (atomics_cobalt_parser_t*) abstract;
|
||||
|
||||
if (!ISINSTANCE (abstract))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
parser->atmospheric = atmospheric;
|
||||
parser->hydrostatic = hydrostatic;
|
||||
parser->hydrostatic = density * GRAVITY;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
@ -151,15 +140,10 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
dc_tank_t *tank = (dc_tank_t *) value;
|
||||
|
||||
double atmospheric = 0.0;
|
||||
unsigned int atmospheric = array_uint16_le (p + 0x26);
|
||||
char buf[BUFLEN];
|
||||
dc_field_string_t *string = (dc_field_string_t *) value;
|
||||
|
||||
if (parser->atmospheric)
|
||||
atmospheric = parser->atmospheric;
|
||||
else
|
||||
atmospheric = array_uint16_le (p + 0x26) * BAR / 1000.0;
|
||||
|
||||
unsigned int workpressure = 0;
|
||||
|
||||
if (value) {
|
||||
@ -168,13 +152,14 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
*((unsigned int *) value) = array_uint16_le (p + 0x58) * 60;
|
||||
break;
|
||||
case DC_FIELD_MAXDEPTH:
|
||||
*((double *) value) = (array_uint16_le (p + 0x56) * BAR / 1000.0 - atmospheric) / parser->hydrostatic;
|
||||
*((double *) value) = (signed int)(array_uint16_le (p + 0x56) - atmospheric) * (BAR / 1000.0) / parser->hydrostatic;
|
||||
break;
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
case DC_FIELD_TANK_COUNT:
|
||||
*((unsigned int *) value) = p[0x2a];
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = p[SZ_HEADER + SZ_GASMIX * flags + 5] / 100.0;
|
||||
gasmix->oxygen = p[SZ_HEADER + SZ_GASMIX * flags + 4] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -206,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]) {
|
||||
@ -220,6 +206,9 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
*((double *) value) = atmospheric / 1000.0;
|
||||
break;
|
||||
case DC_FIELD_STRING:
|
||||
switch(flags) {
|
||||
case 0: // Serialnr
|
||||
@ -274,11 +263,7 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
if (size < header + SZ_SEGMENT * nsegments)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
double atmospheric = 0.0;
|
||||
if (parser->atmospheric)
|
||||
atmospheric = parser->atmospheric;
|
||||
else
|
||||
atmospheric = array_uint16_le (data + 0x26) * BAR / 1000.0;
|
||||
unsigned int atmospheric = array_uint16_le (data + 0x26);
|
||||
|
||||
// Previous gas mix - initialize with impossible value
|
||||
unsigned int gasmix_previous = 0xFFFFFFFF;
|
||||
@ -304,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 = (depth * BAR / 1000.0 - atmospheric) / parser->hydrostatic;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
sample.depth = (signed int)(depth - atmospheric) * (BAR / 1000.0) / parser->hydrostatic;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Pressure (1 psi).
|
||||
unsigned int pressure = array_uint16_le (data + offset + 2);
|
||||
sample.pressure.tank = tank;
|
||||
sample.pressure.value = pressure * PSI / BAR;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
|
||||
// Current gas mix
|
||||
unsigned int gasmix = data[offset + 4];
|
||||
@ -332,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;
|
||||
@ -349,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
|
||||
@ -372,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;
|
||||
}
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
#endif
|
||||
|
||||
#include <stdlib.h> // malloc, free
|
||||
#include <stdio.h>
|
||||
|
||||
#include "socket.h"
|
||||
|
||||
@ -52,7 +51,6 @@
|
||||
#include "context-private.h"
|
||||
#include "iostream-private.h"
|
||||
#include "iterator-private.h"
|
||||
#include "descriptor-private.h"
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -231,7 +229,7 @@ dc_bluetooth_addr2str(dc_bluetooth_address_t address, char *str, size_t size)
|
||||
if (str == NULL || size < DC_BLUETOOTH_SIZE)
|
||||
return NULL;
|
||||
|
||||
int n = snprintf(str, size, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
int n = dc_platform_snprintf(str, size, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
(unsigned char)((address >> 40) & 0xFF),
|
||||
(unsigned char)((address >> 32) & 0xFF),
|
||||
(unsigned char)((address >> 24) & 0xFF),
|
||||
@ -456,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;
|
||||
}
|
||||
|
||||
|
||||
66
src/buffer.c
66
src/buffer.c
@ -231,6 +231,72 @@ dc_buffer_prepend (dc_buffer_t *buffer, const unsigned char data[], size_t size)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
dc_buffer_insert (dc_buffer_t *buffer, size_t offset, const unsigned char data[], size_t size)
|
||||
{
|
||||
if (buffer == NULL)
|
||||
return 0;
|
||||
|
||||
if (offset > buffer->size)
|
||||
return 0;
|
||||
|
||||
size_t head = buffer->offset;
|
||||
size_t tail = buffer->capacity - (buffer->offset + buffer->size);
|
||||
|
||||
unsigned char *ptr = buffer->data + buffer->offset;
|
||||
|
||||
if (size <= head) {
|
||||
if (buffer->size)
|
||||
memmove (ptr - size, ptr, offset);
|
||||
buffer->offset -= size;
|
||||
} else if (size <= tail) {
|
||||
if (buffer->size)
|
||||
memmove (ptr + offset + size, ptr + offset, buffer->size - offset);
|
||||
} else if (size <= tail + head) {
|
||||
size_t n = buffer->size + size;
|
||||
size_t available = buffer->capacity - n;
|
||||
|
||||
size_t tmp_offset = head > tail ? available : 0;
|
||||
|
||||
unsigned char *tmp = buffer->data;
|
||||
|
||||
if (buffer->size) {
|
||||
memmove (tmp + tmp_offset, ptr, offset);
|
||||
memmove (tmp + tmp_offset + offset + size, ptr + offset, buffer->size - offset);
|
||||
}
|
||||
|
||||
buffer->offset = tmp_offset;
|
||||
} else {
|
||||
size_t n = buffer->size + size;
|
||||
size_t capacity = dc_buffer_expand_calc (buffer, n);
|
||||
size_t available = capacity - n;
|
||||
|
||||
size_t tmp_offset = head > tail ? available : 0;
|
||||
|
||||
unsigned char *tmp = (unsigned char *) malloc (capacity);
|
||||
if (tmp == NULL)
|
||||
return 0;
|
||||
|
||||
if (buffer->size) {
|
||||
memcpy (tmp + tmp_offset, ptr, offset);
|
||||
memcpy (tmp + tmp_offset + offset + size, ptr + offset, buffer->size - offset);
|
||||
}
|
||||
|
||||
free (buffer->data);
|
||||
buffer->data = tmp;
|
||||
buffer->capacity = capacity;
|
||||
buffer->offset = tmp_offset;
|
||||
}
|
||||
|
||||
if (size)
|
||||
memcpy (buffer->data + buffer->offset + offset, data, size);
|
||||
|
||||
buffer->size += size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
dc_buffer_slice (dc_buffer_t *buffer, size_t offset, size_t size)
|
||||
{
|
||||
|
||||
180
src/checksum.c
180
src/checksum.c
@ -68,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,9 @@ 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 */
|
||||
citizen_aqualand_parser_get_datetime, /* datetime */
|
||||
citizen_aqualand_parser_get_field, /* fields */
|
||||
citizen_aqualand_parser_samples_foreach, /* samples_foreach */
|
||||
@ -53,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;
|
||||
|
||||
@ -61,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;
|
||||
@ -73,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)
|
||||
{
|
||||
@ -238,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) {
|
||||
@ -257,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,8 +30,6 @@
|
||||
#include "ringbuffer.h"
|
||||
#include "rbstream.h"
|
||||
|
||||
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
|
||||
|
||||
#define MAXRETRIES 2
|
||||
|
||||
#define COCHRAN_MODEL_COMMANDER_TM 0
|
||||
@ -41,6 +39,8 @@
|
||||
#define COCHRAN_MODEL_EMC_16 4
|
||||
#define COCHRAN_MODEL_EMC_20 5
|
||||
|
||||
#define UNDEFINED 0xFFFFFFFF
|
||||
|
||||
typedef enum cochran_endian_t {
|
||||
ENDIAN_LE,
|
||||
ENDIAN_BE,
|
||||
@ -57,8 +57,8 @@ typedef struct cochran_data_t {
|
||||
unsigned char *logbook;
|
||||
|
||||
unsigned short int dive_count;
|
||||
int fp_dive_num;
|
||||
int invalid_profile_dive_num;
|
||||
unsigned int fp_dive_num;
|
||||
unsigned int invalid_profile_dive_num;
|
||||
|
||||
unsigned int logbook_size;
|
||||
} cochran_data_t;
|
||||
@ -621,18 +621,17 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d
|
||||
// We track profile ringbuffer usage to determine which dives have profile data
|
||||
int profile_capacity_remaining = device->layout->rb_profile_end - device->layout->rb_profile_begin;
|
||||
|
||||
int dive_count = -1;
|
||||
data->fp_dive_num = -1;
|
||||
unsigned int dive_count = 0;
|
||||
data->fp_dive_num = UNDEFINED;
|
||||
|
||||
// Start at end of log
|
||||
if (data->dive_count < device->layout->rb_logbook_entry_count)
|
||||
dive_count = data->dive_count;
|
||||
else
|
||||
dive_count = device->layout->rb_logbook_entry_count;
|
||||
dive_count--;
|
||||
|
||||
unsigned int sample_read_size = 0;
|
||||
data->invalid_profile_dive_num = -1;
|
||||
data->invalid_profile_dive_num = UNDEFINED;
|
||||
|
||||
// Remove the pre-dive events that occur after the last dive
|
||||
unsigned int rb_head_ptr = 0;
|
||||
@ -676,7 +675,7 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d
|
||||
|
||||
// Loop through dives to find FP, Accumulate profile data size,
|
||||
// and find the last dive with invalid profile
|
||||
for (unsigned int i = 0; i <= dive_count; ++i) {
|
||||
for (unsigned int i = 0; i < dive_count; ++i) {
|
||||
unsigned int idx = (device->layout->rb_logbook_entry_count + head_dive - (i + 1)) % device->layout->rb_logbook_entry_count;
|
||||
|
||||
unsigned char *log_entry = data->logbook + idx * device->layout->rb_logbook_entry_size;
|
||||
@ -953,7 +952,7 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
|
||||
}
|
||||
|
||||
// Change tail to dive following the fingerprint dive.
|
||||
if (data.fp_dive_num > -1)
|
||||
if (data.fp_dive_num != UNDEFINED)
|
||||
tail_dive = (data.fp_dive_num + 1) % layout->rb_logbook_entry_count;
|
||||
|
||||
// Number of dives to read
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
cochran_commander_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
cochran_commander_parser_create (dc_parser_t **parser, dc_context_t *context, 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
|
||||
}
|
||||
|
||||
@ -29,8 +29,6 @@
|
||||
#include "parser-private.h"
|
||||
#include "array.h"
|
||||
|
||||
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
|
||||
|
||||
#define COCHRAN_MODEL_COMMANDER_TM 0
|
||||
#define COCHRAN_MODEL_COMMANDER_PRE21000 1
|
||||
#define COCHRAN_MODEL_COMMANDER_AIR_NITROX 2
|
||||
@ -101,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);
|
||||
@ -109,7 +106,9 @@ 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 */
|
||||
cochran_commander_parser_get_datetime, /* datetime */
|
||||
cochran_commander_parser_get_field, /* fields */
|
||||
cochran_commander_parser_samples_foreach, /* samples_foreach */
|
||||
@ -314,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -351,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;
|
||||
@ -360,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;
|
||||
@ -406,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)
|
||||
{
|
||||
@ -513,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;
|
||||
@ -577,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) {
|
||||
@ -614,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
|
||||
@ -622,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);
|
||||
@ -635,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++;
|
||||
@ -649,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;
|
||||
@ -713,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
|
||||
@ -773,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
|
||||
@ -781,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
|
||||
@ -790,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;
|
||||
@ -817,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) {
|
||||
@ -833,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
|
||||
@ -854,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:
|
||||
@ -864,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;
|
||||
}
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
|
||||
#include <libdivecomputer/context.h>
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
@ -40,12 +42,6 @@ extern "C" {
|
||||
#define FUNCTION __FUNCTION__
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define ATTR_FORMAT_PRINTF(a,b) __attribute__((format(printf, a, b)))
|
||||
#else
|
||||
#define ATTR_FORMAT_PRINTF(a,b)
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_LOGGING
|
||||
#define HEXDUMP(context, loglevel, prefix, data, size) dc_context_hexdump (context, loglevel, __FILE__, __LINE__, FUNCTION, prefix, data, size)
|
||||
#define SYSERROR(context, errcode) dc_context_syserror (context, DC_LOGLEVEL_ERROR, __FILE__, __LINE__, FUNCTION, errcode)
|
||||
@ -63,7 +59,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
dc_status_t
|
||||
dc_context_log (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *format, ...) ATTR_FORMAT_PRINTF(6, 7);
|
||||
dc_context_log (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *format, ...) DC_ATTR_FORMAT_PRINTF(6, 7);
|
||||
|
||||
dc_status_t
|
||||
dc_context_syserror (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, int errcode);
|
||||
|
||||
@ -25,8 +25,8 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
@ -35,6 +35,7 @@
|
||||
#endif
|
||||
|
||||
#include "context-private.h"
|
||||
#include "platform.h"
|
||||
#include "timer.h"
|
||||
|
||||
struct dc_context_t {
|
||||
@ -48,55 +49,6 @@ struct dc_context_t {
|
||||
};
|
||||
|
||||
#ifdef ENABLE_LOGGING
|
||||
/*
|
||||
* A wrapper for the vsnprintf function, which will always null terminate the
|
||||
* string and returns a negative value if the destination buffer is too small.
|
||||
*/
|
||||
static int
|
||||
l_vsnprintf (char *str, size_t size, const char *format, va_list ap)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (size == 0)
|
||||
return -1;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/*
|
||||
* The non-standard vsnprintf implementation provided by MSVC doesn't null
|
||||
* terminate the string and returns a negative value if the destination
|
||||
* buffer is too small.
|
||||
*/
|
||||
n = _vsnprintf (str, size - 1, format, ap);
|
||||
if (n == size - 1 || n < 0)
|
||||
str[size - 1] = 0;
|
||||
#else
|
||||
/*
|
||||
* The C99 vsnprintf function will always null terminate the string. If the
|
||||
* destination buffer is too small, the return value is the number of
|
||||
* characters that would have been written if the buffer had been large
|
||||
* enough.
|
||||
*/
|
||||
n = vsnprintf (str, size, format, ap);
|
||||
if (n >= size)
|
||||
n = -1;
|
||||
#endif
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
l_snprintf (char *str, size_t size, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int n;
|
||||
|
||||
va_start (ap, format);
|
||||
n = l_vsnprintf (str, size, format, ap);
|
||||
va_end (ap);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static int
|
||||
l_hexdump (char *str, size_t size, const unsigned char data[], size_t n)
|
||||
{
|
||||
@ -104,7 +56,7 @@ l_hexdump (char *str, size_t size, const unsigned char data[], size_t n)
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
|
||||
if (size == 0)
|
||||
if (size == 0 || size > INT_MAX)
|
||||
return -1;
|
||||
|
||||
/* The maximum number of bytes. */
|
||||
@ -126,11 +78,11 @@ l_hexdump (char *str, size_t size, const unsigned char data[], size_t n)
|
||||
/* Null terminate the hex string. */
|
||||
str[length * 2] = 0;
|
||||
|
||||
return (n > maxlength ? -1 : length * 2);
|
||||
return (n > maxlength ? -1 : (int) (length * 2));
|
||||
}
|
||||
|
||||
static void
|
||||
logfunc (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *msg, void *userdata)
|
||||
loghandler (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *msg, void *userdata)
|
||||
{
|
||||
const char *loglevels[] = {"NONE", "ERROR", "WARNING", "INFO", "DEBUG", "ALL"};
|
||||
|
||||
@ -166,7 +118,7 @@ dc_context_new (dc_context_t **out)
|
||||
|
||||
#ifdef ENABLE_LOGGING
|
||||
context->loglevel = DC_LOGLEVEL_WARNING;
|
||||
context->logfunc = logfunc;
|
||||
context->logfunc = loghandler;
|
||||
#else
|
||||
context->loglevel = DC_LOGLEVEL_NONE;
|
||||
context->logfunc = NULL;
|
||||
@ -243,7 +195,7 @@ dc_context_log (dc_context_t *context, dc_loglevel_t loglevel, const char *file,
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
va_start (ap, format);
|
||||
l_vsnprintf (context->msg, sizeof (context->msg), format, ap);
|
||||
dc_platform_vsnprintf (context->msg, sizeof (context->msg), format, ap);
|
||||
va_end (ap);
|
||||
|
||||
context->logfunc (context, loglevel, file, line, function, context->msg, context->userdata);
|
||||
@ -309,7 +261,7 @@ dc_context_hexdump (dc_context_t *context, dc_loglevel_t loglevel, const char *f
|
||||
if (context->logfunc == NULL)
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
n = l_snprintf (context->msg, sizeof (context->msg), "%s: size=%u, data=", prefix, size);
|
||||
n = dc_platform_snprintf (context->msg, sizeof (context->msg), "%s: size=%u, data=", prefix, size);
|
||||
|
||||
if (n >= 0) {
|
||||
n = l_hexdump (context->msg + n, sizeof (context->msg) - n, data, size);
|
||||
|
||||
@ -38,6 +38,8 @@
|
||||
#define SZ_PACKET 0x80
|
||||
#define SZ_PAGE (SZ_PACKET / 4)
|
||||
|
||||
#define SZ_HEADER 32
|
||||
|
||||
#define IQ700 0x05
|
||||
#define EDY 0x08
|
||||
|
||||
@ -379,7 +381,14 @@ cressi_edy_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
return device_dump_read (abstract, dc_buffer_get_data (buffer),
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = device->model;
|
||||
devinfo.firmware = 0;
|
||||
devinfo.serial = 0;
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
return device_dump_read (abstract, 0, dc_buffer_get_data (buffer),
|
||||
dc_buffer_get_size (buffer), SZ_PACKET);
|
||||
}
|
||||
|
||||
@ -515,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,9 @@ 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 */
|
||||
cressi_edy_parser_get_datetime, /* datetime */
|
||||
cressi_edy_parser_get_field, /* fields */
|
||||
cressi_edy_parser_samples_foreach, /* samples_foreach */
|
||||
@ -70,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;
|
||||
|
||||
@ -78,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;
|
||||
@ -93,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;
|
||||
@ -127,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;
|
||||
@ -149,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;
|
||||
@ -185,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};
|
||||
|
||||
@ -198,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) {
|
||||
@ -217,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;
|
||||
@ -485,7 +485,19 @@ cressi_goa_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
|
||||
goto error_free_dive;
|
||||
}
|
||||
|
||||
if (callback && !callback(dive_data, dive_size, dive_data + FP_OFFSET - 5, sizeof(device->fingerprint), userdata))
|
||||
// Those 5 extra bytes contain the dive mode, which is required for
|
||||
// parsing the dive data. Therefore, insert all 5 bytes again. The
|
||||
// remaining 4 bytes appear to be some 32 bit address.
|
||||
if (!dc_buffer_insert (dive, 2, logbook_data + offset + 2, 5)) {
|
||||
ERROR (abstract->context, "Out of memory.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free_dive;
|
||||
}
|
||||
|
||||
dive_data = dc_buffer_get_data (dive);
|
||||
dive_size = dc_buffer_get_size (dive);
|
||||
|
||||
if (callback && !callback(dive_data, dive_size, dive_data + FP_OFFSET, sizeof(device->fingerprint), userdata))
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
cressi_goa_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
cressi_goa_parser_create (dc_parser_t **parser, dc_context_t *context, 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
|
||||
}
|
||||
|
||||
@ -28,22 +28,40 @@
|
||||
|
||||
#define ISINSTANCE(parser) dc_device_isinstance((parser), &cressi_goa_parser_vtable)
|
||||
|
||||
#define SZ_HEADER 0x5C
|
||||
#define SZ_HEADER 23
|
||||
|
||||
#define DEPTH 0
|
||||
#define DEPTH2 1
|
||||
#define TIME 2
|
||||
#define TEMPERATURE 3
|
||||
|
||||
#define SCUBA 0
|
||||
#define NITROX 1
|
||||
#define FREEDIVE 2
|
||||
#define GAUGE 3
|
||||
|
||||
#define NGASMIXES 2
|
||||
|
||||
#define UNDEFINED 0xFFFFFFFF
|
||||
|
||||
typedef struct cressi_goa_parser_t cressi_goa_parser_t;
|
||||
|
||||
struct cressi_goa_parser_t {
|
||||
dc_parser_t base;
|
||||
unsigned int model;
|
||||
// Cached fields.
|
||||
unsigned int cached;
|
||||
double maxdepth;
|
||||
};
|
||||
|
||||
static dc_status_t cressi_goa_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
typedef struct cressi_goa_layout_t {
|
||||
unsigned int headersize;
|
||||
unsigned int datetime;
|
||||
unsigned int divetime;
|
||||
unsigned int gasmix;
|
||||
unsigned int atmospheric;
|
||||
unsigned int maxdepth;
|
||||
unsigned int avgdepth;
|
||||
unsigned int temperature;
|
||||
} cressi_goa_layout_t;
|
||||
|
||||
static dc_status_t cressi_goa_parser_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);
|
||||
@ -51,15 +69,64 @@ 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 */
|
||||
cressi_goa_parser_get_datetime, /* datetime */
|
||||
cressi_goa_parser_get_field, /* fields */
|
||||
cressi_goa_parser_samples_foreach, /* samples_foreach */
|
||||
NULL /* destroy */
|
||||
};
|
||||
|
||||
static const cressi_goa_layout_t layouts[] = {
|
||||
/* SCUBA */
|
||||
{
|
||||
0x61, /* headersize */
|
||||
0x11, /* datetime */
|
||||
0x19, /* divetime */
|
||||
0x1F, /* gasmix */
|
||||
0x23, /* atmospheric */
|
||||
0x4E, /* maxdepth */
|
||||
0x50, /* avgdepth */
|
||||
0x52, /* temperature */
|
||||
},
|
||||
/* NITROX */
|
||||
{
|
||||
0x61, /* headersize */
|
||||
0x11, /* datetime */
|
||||
0x19, /* divetime */
|
||||
0x1F, /* gasmix */
|
||||
0x23, /* atmospheric */
|
||||
0x4E, /* maxdepth */
|
||||
0x50, /* avgdepth */
|
||||
0x52, /* temperature */
|
||||
},
|
||||
/* FREEDIVE */
|
||||
{
|
||||
0x2B, /* headersize */
|
||||
0x11, /* datetime */
|
||||
0x19, /* divetime */
|
||||
UNDEFINED, /* gasmix */
|
||||
UNDEFINED, /* atmospheric */
|
||||
0x1C, /* maxdepth */
|
||||
UNDEFINED, /* avgdepth */
|
||||
0x1E, /* temperature */
|
||||
},
|
||||
/* GAUGE */
|
||||
{
|
||||
0x2D, /* headersize */
|
||||
0x11, /* datetime */
|
||||
0x19, /* divetime */
|
||||
UNDEFINED, /* gasmix */
|
||||
0x1B, /* atmospheric */
|
||||
0x1D, /* maxdepth */
|
||||
0x1F, /* avgdepth */
|
||||
0x21, /* temperature */
|
||||
},
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, 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;
|
||||
|
||||
@ -67,47 +134,46 @@ 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;
|
||||
}
|
||||
|
||||
parser->model = model;
|
||||
parser->cached = 0;
|
||||
parser->maxdepth = 0.0;
|
||||
|
||||
*out = (dc_parser_t*) parser;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
cressi_goa_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
cressi_goa_parser_t *parser = (cressi_goa_parser_t *) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 0;
|
||||
parser->maxdepth = 0.0;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
if (abstract->size < SZ_HEADER)
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
if (size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
const unsigned char *p = abstract->data;
|
||||
unsigned int divemode = data[2];
|
||||
if (divemode >= C_ARRAY_SIZE(layouts)) {
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
const cressi_goa_layout_t *layout = &layouts[divemode];
|
||||
|
||||
if (size < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
const unsigned char *p = abstract->data + layout->datetime;
|
||||
|
||||
if (datetime) {
|
||||
datetime->year = array_uint16_le(p + 0x0C);
|
||||
datetime->month = p[0x0E];
|
||||
datetime->day = p[0x0F];
|
||||
datetime->hour = p[0x10];
|
||||
datetime->minute = p[0x11];
|
||||
datetime->year = array_uint16_le(p);
|
||||
datetime->month = p[2];
|
||||
datetime->day = p[3];
|
||||
datetime->hour = p[4];
|
||||
datetime->minute = p[5];
|
||||
datetime->second = 0;
|
||||
datetime->timezone = DC_TIMEZONE_NONE;
|
||||
}
|
||||
@ -118,21 +184,29 @@ cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
static dc_status_t
|
||||
cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
|
||||
{
|
||||
cressi_goa_parser_t *parser = (cressi_goa_parser_t *) abstract;
|
||||
if (abstract->size < SZ_HEADER)
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
if (size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int divemode = data[2];
|
||||
if (divemode >= C_ARRAY_SIZE(layouts)) {
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
if (!parser->cached) {
|
||||
sample_statistics_t statistics = SAMPLE_STATISTICS_INITIALIZER;
|
||||
dc_status_t rc = cressi_goa_parser_samples_foreach (
|
||||
abstract, sample_statistics_cb, &statistics);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
const cressi_goa_layout_t *layout = &layouts[divemode];
|
||||
|
||||
parser->cached = 1;
|
||||
parser->maxdepth = statistics.maxdepth;
|
||||
if (size < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int ngasmixes = 0;
|
||||
if (layout->gasmix != UNDEFINED) {
|
||||
for (unsigned int i = 0; i < NGASMIXES; ++i) {
|
||||
if (data[layout->gasmix + 2 * i + 1] == 0)
|
||||
break;
|
||||
ngasmixes++;
|
||||
}
|
||||
}
|
||||
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
@ -140,19 +214,55 @@ cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
||||
if (value) {
|
||||
switch (type) {
|
||||
case DC_FIELD_DIVETIME:
|
||||
*((unsigned int *) value) = array_uint16_le (data + 0x14);
|
||||
if (layout->divetime == UNDEFINED)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((unsigned int *) value) = array_uint16_le (data + layout->divetime);
|
||||
break;
|
||||
case DC_FIELD_MAXDEPTH:
|
||||
*((double *) value) = parser->maxdepth;
|
||||
if (layout->maxdepth == UNDEFINED)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((double *) value) = array_uint16_le (data + layout->maxdepth) / 10.0;
|
||||
break;
|
||||
case DC_FIELD_AVGDEPTH:
|
||||
if (layout->avgdepth == UNDEFINED)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((double *) value) = array_uint16_le (data + layout->avgdepth) / 10.0;
|
||||
break;
|
||||
case DC_FIELD_TEMPERATURE_MINIMUM:
|
||||
if (layout->temperature == UNDEFINED)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((double *) value) = array_uint16_le (data + layout->temperature) / 10.0;
|
||||
break;
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
if (layout->atmospheric == UNDEFINED)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((double *) value) = array_uint16_le (data + layout->atmospheric) / 1000.0;
|
||||
break;
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
*((unsigned int *) value) = 2;
|
||||
*((unsigned int *) value) = ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->oxygen = data[0x1B + 2 * flags] / 100.0;
|
||||
gasmix->oxygen = data[layout->gasmix + 2 * flags + 1] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
break;
|
||||
case DC_FIELD_DIVEMODE:
|
||||
switch (divemode) {
|
||||
case SCUBA:
|
||||
case NITROX:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_OC;
|
||||
break;
|
||||
case GAUGE:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_GAUGE;
|
||||
break;
|
||||
case FREEDIVE:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_FREEDIVE;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
@ -167,12 +277,29 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
unsigned int time = 0;
|
||||
unsigned int interval = 5;
|
||||
unsigned int complete = 1;
|
||||
unsigned int gasmix_previous = 0xFFFFFFFF;
|
||||
if (size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int offset = SZ_HEADER;
|
||||
unsigned int divemode = data[2];
|
||||
if (divemode >= C_ARRAY_SIZE(layouts)) {
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
const cressi_goa_layout_t *layout = &layouts[divemode];
|
||||
|
||||
if (size < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int interval = divemode == FREEDIVE ? 2 : 5;
|
||||
|
||||
unsigned int time = 0;
|
||||
unsigned int depth = 0;
|
||||
unsigned int gasmix = 0, gasmix_previous = 0xFFFFFFFF;
|
||||
unsigned int temperature = 0;
|
||||
unsigned int have_temperature = 0;
|
||||
unsigned int complete = 0;
|
||||
|
||||
unsigned int offset = layout->headersize;
|
||||
while (offset + 2 <= size) {
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
@ -181,35 +308,44 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
unsigned int type = (raw & 0x0003);
|
||||
unsigned int value = (raw & 0xFFFC) >> 2;
|
||||
|
||||
if (complete) {
|
||||
// Time (seconds).
|
||||
if (type == DEPTH || type == DEPTH2) {
|
||||
depth = (value & 0x07FF);
|
||||
gasmix = (value & 0x0800) >> 11;
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
complete = 0;
|
||||
}
|
||||
|
||||
if (type == DEPTH) {
|
||||
// Depth (1/10 m).
|
||||
unsigned int depth = value & 0x07FF;
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
|
||||
// Gas change.
|
||||
unsigned int gasmix = (value & 0x0800) >> 11;
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
complete = 1;
|
||||
} else if (type == TEMPERATURE) {
|
||||
temperature = value;
|
||||
have_temperature = 1;
|
||||
} else if (type == TIME) {
|
||||
time += value;
|
||||
}
|
||||
|
||||
if (complete) {
|
||||
// Time (seconds).
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Temperature (1/10 °C).
|
||||
sample.temperature = value / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
} else {
|
||||
WARNING(abstract->context, "Unknown sample type %u.", type);
|
||||
if (have_temperature) {
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
have_temperature = 0;
|
||||
}
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Gas change
|
||||
if (divemode == SCUBA || divemode == NITROX) {
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
}
|
||||
|
||||
complete = 0;
|
||||
}
|
||||
|
||||
offset += 2;
|
||||
|
||||
@ -84,7 +84,7 @@ cressi_leonardo_make_ascii (const unsigned char raw[], unsigned int rsize, unsig
|
||||
array_convert_bin2hex (raw, rsize, ascii + 1, 2 * rsize);
|
||||
|
||||
// Checksum
|
||||
unsigned short crc = checksum_crc16_ccitt (ascii + 1, 2 * rsize, 0xffff);
|
||||
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,12 +372,19 @@ 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;
|
||||
}
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = data[0];
|
||||
devinfo.firmware = 0;
|
||||
devinfo.serial = array_uint24_le (data + 1);
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -394,13 +401,6 @@ cressi_leonardo_device_foreach (dc_device_t *abstract, dc_dive_callback_t callba
|
||||
return rc;
|
||||
}
|
||||
|
||||
unsigned char *data = dc_buffer_get_data (buffer);
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = data[0];
|
||||
devinfo.firmware = 0;
|
||||
devinfo.serial = array_uint24_le (data + 1);
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
rc = cressi_leonardo_extract_dives (abstract, dc_buffer_get_data (buffer),
|
||||
dc_buffer_get_size (buffer), callback, userdata);
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
cressi_leonardo_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
cressi_leonardo_parser_create (dc_parser_t **parser, dc_context_t *context, 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,9 @@ 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 */
|
||||
cressi_leonardo_parser_get_datetime, /* datetime */
|
||||
cressi_leonardo_parser_get_field, /* fields */
|
||||
cressi_leonardo_parser_samples_foreach, /* samples_foreach */
|
||||
@ -56,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;
|
||||
|
||||
@ -64,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;
|
||||
@ -78,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)
|
||||
{
|
||||
@ -143,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;
|
||||
@ -178,6 +173,9 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
|
||||
unsigned int gasmix_previous = 0xFFFFFFFF;
|
||||
unsigned int gasmix = 0;
|
||||
if (parser->model == DRAKE) {
|
||||
gasmix = gasmix_previous;
|
||||
}
|
||||
|
||||
unsigned int offset = SZ_HEADER;
|
||||
while (offset + 2 <= size) {
|
||||
@ -190,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 {
|
||||
@ -205,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;
|
||||
}
|
||||
|
||||
@ -223,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;
|
||||
|
||||
500
src/deepblu.c
500
src/deepblu.c
@ -1,500 +0,0 @@
|
||||
/*
|
||||
* Deepblu Cosmiq+ downloading
|
||||
*
|
||||
* Copyright (C) 2019 Linus Torvalds
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "deepblu.h"
|
||||
#include "context-private.h"
|
||||
#include "device-private.h"
|
||||
#include "array.h"
|
||||
|
||||
// "Write state"
|
||||
#define CMD_SETTIME 0x20 // Send 6 byte date-time, get single-byte 00x00 ack
|
||||
#define CMD_23 0x23 // Send 00/01 byte, get ack back? Some metric/imperial setting?
|
||||
|
||||
// "Read dives"?
|
||||
#define CMD_GETDIVENR 0x40 // Send empty byte, get single-byte number of dives back
|
||||
#define CMD_GETDIVE 0x41 // Send dive number (1-nr) byte, get dive stat length byte back
|
||||
#define RSP_DIVESTAT 0x42 // .. followed by packets of dive stat for that dive of that length
|
||||
#define CMD_GETPROFILE 0x43 // Send dive number (1-nr) byte, get dive profile length BE word back
|
||||
#define RSP_DIVEPROF 0x44 // .. followed by packets of dive profile of that length
|
||||
|
||||
// "Read state"
|
||||
#define CMD_GETTIME 0x50 // Send empty byte, get six-byte bcd date-time back
|
||||
#define CMD_51 0x51 // Send empty byte, get four bytes back (03 dc 00 e3)
|
||||
#define CMD_52 0x52 // Send empty byte, get two bytes back (bf 8d)
|
||||
#define CMD_53 0x53 // Send empty byte, get six bytes back (0e 81 00 03 00 00)
|
||||
#define CMD_54 0x54 // Send empty byte, get byte back (00)
|
||||
#define CMD_55 0x55 // Send empty byte, get byte back (00)
|
||||
#define CMD_56 0x56 // Send empty byte, get byte back (00)
|
||||
#define CMD_57 0x57 // Send empty byte, get byte back (00)
|
||||
#define CMD_58 0x58 // Send empty byte, get byte back (52)
|
||||
#define CMD_59 0x59 // Send empty byte, get six bytes back (00 00 07 00 00 00)
|
||||
// (00 00 00 00 00 00)
|
||||
#define CMD_5a 0x5a // Send empty byte, get six bytes back (23 1b 09 d8 37 c0)
|
||||
#define CMD_5b 0x5b // Send empty byte, get six bytes back (00 21 00 14 00 01)
|
||||
// (00 00 00 14 00 01)
|
||||
#define CMD_5c 0x5c // Send empty byte, get six bytes back (13 88 00 46 20 00)
|
||||
// (13 88 00 3c 15 00)
|
||||
#define CMD_5d 0x5d // Send empty byte, get six bytes back (19 00 23 0C 02 0E)
|
||||
// (14 14 14 0c 01 0e)
|
||||
#define CMD_5f 0x5f // Send empty byte, get six bytes back (00 00 07 00 00 00)
|
||||
|
||||
#define COSMIQ_HDR_SIZE 36
|
||||
|
||||
typedef struct deepblu_device_t {
|
||||
dc_device_t base;
|
||||
dc_iostream_t *iostream;
|
||||
unsigned char fingerprint[COSMIQ_HDR_SIZE];
|
||||
} deepblu_device_t;
|
||||
|
||||
static dc_status_t deepblu_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||
static dc_status_t deepblu_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
||||
static dc_status_t deepblu_device_timesync(dc_device_t *abstract, const dc_datetime_t *datetime);
|
||||
static dc_status_t deepblu_device_close (dc_device_t *abstract);
|
||||
|
||||
static const dc_device_vtable_t deepblu_device_vtable = {
|
||||
sizeof(deepblu_device_t),
|
||||
DC_FAMILY_DEEPBLU,
|
||||
deepblu_device_set_fingerprint, /* set_fingerprint */
|
||||
NULL, /* read */
|
||||
NULL, /* write */
|
||||
NULL, /* dump */
|
||||
deepblu_device_foreach, /* foreach */
|
||||
deepblu_device_timesync, /* timesync */
|
||||
deepblu_device_close, /* close */
|
||||
};
|
||||
|
||||
// Maximum data in a packet. It's actually much
|
||||
// less than this, since BLE packets are small and
|
||||
// with the 7 bytes of headers and final newline
|
||||
// and the HEX encoding, the actual maximum is
|
||||
// just something like 6 bytes.
|
||||
//
|
||||
// But in theory the data could be done over
|
||||
// multiple packets. That doesn't seem to be
|
||||
// the case in anything I've seen so far.
|
||||
//
|
||||
// Pick something small and easy to use for
|
||||
// stack buffers.
|
||||
#define MAX_DATA 20
|
||||
|
||||
static char *
|
||||
write_hex_byte(unsigned char data, char *p)
|
||||
{
|
||||
static const char hex[16] = "0123456789ABCDEF";
|
||||
*p++ = hex[data >> 4];
|
||||
*p++ = hex[data & 0xf];
|
||||
return p;
|
||||
}
|
||||
|
||||
//
|
||||
// Send a cmd packet.
|
||||
//
|
||||
// The format of the cmd on the "wire" is:
|
||||
// - byte '#'
|
||||
// - HEX char of cmd
|
||||
// - HEX char two's complement modular sum of packet data (including cmd/size)
|
||||
// - HEX char size of data as encoded in HEX
|
||||
// - n * HEX char data
|
||||
// - byte '\n'
|
||||
// so you end up having 8 bytes of header/trailer overhead, and two bytes
|
||||
// for every byte of data sent due to the HEX encoding.
|
||||
//
|
||||
static dc_status_t
|
||||
deepblu_send_cmd(deepblu_device_t *device, const unsigned char cmd, const unsigned char data[], size_t size)
|
||||
{
|
||||
char buffer[8+2*MAX_DATA], *p;
|
||||
unsigned char csum;
|
||||
int i;
|
||||
|
||||
if (size > MAX_DATA)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Calculate packet csum
|
||||
csum = cmd + 2*size;
|
||||
for (i = 0; i < size; i++)
|
||||
csum += data[i];
|
||||
csum = -csum;
|
||||
|
||||
// Fill the data buffer
|
||||
p = buffer;
|
||||
*p++ = '#';
|
||||
p = write_hex_byte(cmd, p);
|
||||
p = write_hex_byte(csum, p);
|
||||
p = write_hex_byte(size*2, p);
|
||||
for (i = 0; i < size; i++)
|
||||
p = write_hex_byte(data[i], p);
|
||||
*p++ = '\n';
|
||||
|
||||
// .. and send it out
|
||||
return dc_iostream_write(device->iostream, buffer, p-buffer, NULL);
|
||||
}
|
||||
|
||||
//
|
||||
// Receive one 'line' of data
|
||||
//
|
||||
// The deepblu BLE protocol is ASCII line based and packetized.
|
||||
// Normally one packet is one line, but it looks like the Nordic
|
||||
// Semi BLE chip will sometimes send packets early (some internal
|
||||
// serial buffer timeout?) with incompete data.
|
||||
//
|
||||
// So read packets until you get newline.
|
||||
static dc_status_t
|
||||
deepblu_recv_line(deepblu_device_t *device, unsigned char *buf, size_t size)
|
||||
{
|
||||
while (1) {
|
||||
unsigned char buffer[20];
|
||||
size_t transferred = 0;
|
||||
dc_status_t status;
|
||||
|
||||
status = dc_iostream_read(device->iostream, buffer, sizeof(buffer), &transferred);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR(device->base.context, "Failed to receive Deepblu reply packet.");
|
||||
return status;
|
||||
}
|
||||
if (transferred > size) {
|
||||
ERROR(device->base.context, "Deepblu reply packet with too much data (got %zu, expected %zu)", transferred, size);
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
if (!transferred) {
|
||||
ERROR(device->base.context, "Empty Deepblu reply packet");
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
memcpy(buf, buffer, transferred);
|
||||
buf += transferred;
|
||||
size -= transferred;
|
||||
if (buf[-1] == '\n')
|
||||
break;
|
||||
}
|
||||
buf[-1] = 0;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
hex_nibble(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
read_hex_byte(char *p)
|
||||
{
|
||||
// This is negative if either of the nibbles is invalid
|
||||
return (hex_nibble(p[0]) << 4) | hex_nibble(p[1]);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Receive a reply packet
|
||||
//
|
||||
// The reply packet has the same format as the cmd packet we
|
||||
// send, except the first byte is '$' instead of '#'.
|
||||
static dc_status_t
|
||||
deepblu_recv_data(deepblu_device_t *device, const unsigned char expected, unsigned char *buf, size_t size, size_t *received)
|
||||
{
|
||||
int len, i;
|
||||
dc_status_t status;
|
||||
char buffer[8+2*MAX_DATA];
|
||||
int cmd, csum, ndata;
|
||||
|
||||
status = deepblu_recv_line(device, buffer, sizeof(buffer));
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
// deepblu_recv_line() always zero-terminates the result
|
||||
// if it returned success, and has removed the final newline.
|
||||
len = strlen(buffer);
|
||||
HEXDUMP(device->base.context, DC_LOGLEVEL_DEBUG, "rcv", buffer, len);
|
||||
|
||||
// A valid reply should always be at least 7 characters: the
|
||||
// initial '$' and the three header HEX bytes.
|
||||
if (len < 8 || buffer[0] != '$') {
|
||||
ERROR(device->base.context, "Invalid Deepblu reply packet");
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
cmd = read_hex_byte(buffer+1);
|
||||
csum = read_hex_byte(buffer+3);
|
||||
ndata = read_hex_byte(buffer+5);
|
||||
if ((cmd | csum | ndata) < 0) {
|
||||
ERROR(device->base.context, "non-hex Deepblu reply packet header");
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
// Verify the data length: it's the size of the HEX data,
|
||||
// and should also match the line length we got (the 7
|
||||
// is for the header data we already decoded above).
|
||||
if ((ndata & 1) || ndata != len - 7) {
|
||||
ERROR(device->base.context, "Deepblu reply packet data length does not match (claimed %d, got %d)", ndata, len-7);
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
if (ndata >> 1 > size) {
|
||||
ERROR(device->base.context, "Deepblu reply packet too big for buffer (ndata=%d, size=%zu)", ndata, size);
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
csum += cmd + ndata;
|
||||
|
||||
for (i = 7; i < len; i += 2) {
|
||||
int byte = read_hex_byte(buffer + i);
|
||||
if (byte < 0) {
|
||||
ERROR(device->base.context, "Deepblu reply packet data not valid hex");
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
*buf++ = byte;
|
||||
csum += byte;
|
||||
}
|
||||
|
||||
if (csum & 255) {
|
||||
ERROR(device->base.context, "Deepblu reply packet csum not valid (%x)", csum);
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
|
||||
*received = ndata >> 1;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Common communication pattern: send a command, expect data back with the same
|
||||
// command byte.
|
||||
static dc_status_t
|
||||
deepblu_send_recv(deepblu_device_t *device, const unsigned char cmd,
|
||||
const unsigned char *data, size_t data_size,
|
||||
unsigned char *result, size_t result_size)
|
||||
{
|
||||
dc_status_t status;
|
||||
size_t got;
|
||||
|
||||
status = deepblu_send_cmd(device, cmd, data, data_size);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
status = deepblu_recv_data(device, cmd, result, result_size, &got);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
if (got != result_size) {
|
||||
ERROR(device->base.context, "Deepblu result size didn't match expected (expected %zu, got %zu)",
|
||||
result_size, got);
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_recv_bulk(deepblu_device_t *device, const unsigned char cmd, unsigned char *buf, size_t len)
|
||||
{
|
||||
while (len) {
|
||||
dc_status_t status;
|
||||
size_t got;
|
||||
|
||||
status = deepblu_recv_data(device, cmd, buf, len, &got);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
if (got > len) {
|
||||
ERROR(device->base.context, "Deepblu bulk receive overflow");
|
||||
return DC_STATUS_IO;
|
||||
}
|
||||
buf += got;
|
||||
len -= got;
|
||||
}
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
deepblu_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream)
|
||||
{
|
||||
deepblu_device_t *device;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
device = (deepblu_device_t *) dc_device_allocate (context, &deepblu_device_vtable);
|
||||
if (device == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
device->iostream = iostream;
|
||||
memset(device->fingerprint, 0, sizeof(device->fingerprint));
|
||||
|
||||
*out = (dc_device_t *) device;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
|
||||
{
|
||||
deepblu_device_t *device = (deepblu_device_t *)abstract;
|
||||
|
||||
HEXDUMP(device->base.context, DC_LOGLEVEL_DEBUG, "set_fingerprint", data, size);
|
||||
|
||||
if (size && size != sizeof (device->fingerprint))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (size)
|
||||
memcpy (device->fingerprint, data, sizeof (device->fingerprint));
|
||||
else
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static unsigned char bcd(int val)
|
||||
{
|
||||
if (val >= 0 && val < 100) {
|
||||
int high = val / 10;
|
||||
int low = val % 10;
|
||||
return (high << 4) | low;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_device_timesync(dc_device_t *abstract, const dc_datetime_t *datetime)
|
||||
{
|
||||
deepblu_device_t *device = (deepblu_device_t *)abstract;
|
||||
unsigned char result[1], data[6];
|
||||
dc_status_t status;
|
||||
size_t len;
|
||||
|
||||
data[0] = bcd(datetime->year - 2000);
|
||||
data[1] = bcd(datetime->month);
|
||||
data[2] = bcd(datetime->day);
|
||||
data[3] = bcd(datetime->hour);
|
||||
data[4] = bcd(datetime->minute);
|
||||
data[5] = bcd(datetime->second);
|
||||
|
||||
// Maybe also check that we received one zero byte (ack?)
|
||||
return deepblu_send_recv(device, CMD_SETTIME,
|
||||
data, sizeof(data),
|
||||
result, sizeof(result));
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_device_close (dc_device_t *abstract)
|
||||
{
|
||||
deepblu_device_t *device = (deepblu_device_t *) abstract;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static const char zero[MAX_DATA];
|
||||
|
||||
static dc_status_t
|
||||
deepblu_download_dive(deepblu_device_t *device, unsigned char nr, dc_dive_callback_t callback, void *userdata)
|
||||
{
|
||||
unsigned char header_len;
|
||||
unsigned char profilebytes[2];
|
||||
unsigned int profile_len;
|
||||
dc_status_t status;
|
||||
char header[256];
|
||||
unsigned char *profile;
|
||||
|
||||
status = deepblu_send_recv(device, CMD_GETDIVE, &nr, 1, &header_len, 1);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
status = deepblu_recv_bulk(device, RSP_DIVESTAT, header, header_len);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
memset(header + header_len, 0, 256 - header_len);
|
||||
|
||||
/* The header is the fingerprint. If we've already seen this header, we're done */
|
||||
if (memcmp(header, device->fingerprint, sizeof (device->fingerprint)) == 0)
|
||||
return DC_STATUS_DONE;
|
||||
|
||||
status = deepblu_send_recv(device, CMD_GETPROFILE, &nr, 1, profilebytes, sizeof(profilebytes));
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
profile_len = (profilebytes[0] << 8) | profilebytes[1];
|
||||
|
||||
profile = malloc(256 + profile_len);
|
||||
if (!profile) {
|
||||
ERROR (device->base.context, "Insufficient buffer space available.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// We make the dive data be 256 bytes of header, followed by the profile data
|
||||
memcpy(profile, header, 256);
|
||||
|
||||
status = deepblu_recv_bulk(device, RSP_DIVEPROF, profile+256, profile_len);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (callback) {
|
||||
if (!callback(profile, profile_len+256, header, header_len, userdata))
|
||||
return DC_STATUS_DONE;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
|
||||
{
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
deepblu_device_t *device = (deepblu_device_t *) abstract;
|
||||
unsigned char nrdives, val;
|
||||
dc_status_t status;
|
||||
int i;
|
||||
|
||||
val = 0;
|
||||
status = deepblu_send_recv(device, CMD_GETDIVENR, &val, 1, &nrdives, 1);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (!nrdives)
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
progress.maximum = nrdives;
|
||||
progress.current = 0;
|
||||
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
for (i = 1; i <= nrdives; i++) {
|
||||
if (device_is_cancelled(abstract)) {
|
||||
dc_status_set_error(&status, DC_STATUS_CANCELLED);
|
||||
break;
|
||||
}
|
||||
|
||||
status = deepblu_download_dive(device, i, callback, userdata);
|
||||
switch (status) {
|
||||
case DC_STATUS_DONE:
|
||||
i = nrdives;
|
||||
break;
|
||||
case DC_STATUS_SUCCESS:
|
||||
break;
|
||||
default:
|
||||
return status;
|
||||
}
|
||||
progress.current = i;
|
||||
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
548
src/deepblu_cosmiq.c
Normal file
548
src/deepblu_cosmiq.c
Normal file
@ -0,0 +1,548 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2019 Linus Torvalds
|
||||
* Copyright (C) 2022 Jef Driesen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "deepblu_cosmiq.h"
|
||||
#include "context-private.h"
|
||||
#include "device-private.h"
|
||||
#include "platform.h"
|
||||
#include "checksum.h"
|
||||
#include "array.h"
|
||||
|
||||
// Maximum data in a packet. It's actually much
|
||||
// less than this, since BLE packets are small and
|
||||
// with the 7 bytes of headers and final newline
|
||||
// and the HEX encoding, the actual maximum is
|
||||
// just something like 6 bytes.
|
||||
//
|
||||
// But in theory the data could be done over
|
||||
// multiple packets. That doesn't seem to be
|
||||
// the case in anything I've seen so far.
|
||||
//
|
||||
// Pick something small and easy to use for
|
||||
// stack buffers.
|
||||
#define MAX_DATA 20
|
||||
|
||||
#define SZ_HEADER 36
|
||||
|
||||
#define FP_OFFSET 6
|
||||
#define FP_SIZE 6
|
||||
|
||||
#define CMD_SET_DATETIME 0x20
|
||||
|
||||
#define CMD_DIVE_COUNT 0x40
|
||||
#define CMD_DIVE_HEADER 0x41
|
||||
#define CMD_DIVE_HEADER_DATA 0x42
|
||||
#define CMD_DIVE_PROFILE 0x43
|
||||
#define CMD_DIVE_PROFILE_DATA 0x44
|
||||
|
||||
#define CMD_SYSTEM_FW 0x58
|
||||
#define CMD_SYSTEM_MAC 0x5A
|
||||
|
||||
#define NSTEPS 1000
|
||||
#define STEP(i,n) (NSTEPS * (i) / (n))
|
||||
|
||||
typedef struct deepblu_cosmiq_device_t {
|
||||
dc_device_t base;
|
||||
dc_iostream_t *iostream;
|
||||
unsigned char fingerprint[FP_SIZE];
|
||||
} deepblu_cosmiq_device_t;
|
||||
|
||||
static dc_status_t deepblu_cosmiq_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||
static dc_status_t deepblu_cosmiq_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
||||
static dc_status_t deepblu_cosmiq_device_timesync(dc_device_t *abstract, const dc_datetime_t *datetime);
|
||||
|
||||
static const dc_device_vtable_t deepblu_cosmiq_device_vtable = {
|
||||
sizeof(deepblu_cosmiq_device_t),
|
||||
DC_FAMILY_DEEPBLU_COSMIQ,
|
||||
deepblu_cosmiq_device_set_fingerprint, /* set_fingerprint */
|
||||
NULL, /* read */
|
||||
NULL, /* write */
|
||||
NULL, /* dump */
|
||||
deepblu_cosmiq_device_foreach, /* foreach */
|
||||
deepblu_cosmiq_device_timesync, /* timesync */
|
||||
NULL, /* close */
|
||||
};
|
||||
|
||||
//
|
||||
// Send a cmd packet.
|
||||
//
|
||||
// The format of the cmd on the "wire" is:
|
||||
// - byte '#'
|
||||
// - HEX char of cmd
|
||||
// - HEX char two's complement modular sum of packet data (including cmd/size)
|
||||
// - HEX char size of data as encoded in HEX
|
||||
// - n * HEX char data
|
||||
// - byte '\n'
|
||||
// so you end up having 8 bytes of header/trailer overhead, and two bytes
|
||||
// for every byte of data sent due to the HEX encoding.
|
||||
//
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_send (deepblu_cosmiq_device_t *device, const unsigned char cmd, const unsigned char data[], size_t size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
if (size > MAX_DATA)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (device_is_cancelled (abstract))
|
||||
return DC_STATUS_CANCELLED;
|
||||
|
||||
// Build the packet.
|
||||
unsigned char csum = ~checksum_add_uint8 (data, size, cmd + 2 * size) + 1;
|
||||
unsigned char raw[3 + MAX_DATA] = {
|
||||
cmd,
|
||||
csum,
|
||||
2 * size
|
||||
};
|
||||
if (size) {
|
||||
memcpy (raw + 3, data, size);
|
||||
}
|
||||
unsigned char packet[1 + 2 * (3 + MAX_DATA) + 1] = {0};
|
||||
packet[0] = '#';
|
||||
array_convert_bin2hex (raw, 3 + size, packet + 1, 2 * (3 + size));
|
||||
packet[1 + 2 * (3 + size)] = '\n';
|
||||
|
||||
HEXDUMP (device->base.context, DC_LOGLEVEL_DEBUG, "cmd", raw, 3 + size);
|
||||
|
||||
// Send the command.
|
||||
status = dc_iostream_write (device->iostream, packet, 2 + 2 * (3 + size), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (device->base.context, "Failed to send the command.");
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//
|
||||
// Receive one 'line' of data
|
||||
//
|
||||
// The deepblu BLE protocol is ASCII line based and packetized.
|
||||
// Normally one packet is one line, but it looks like the Nordic
|
||||
// Semi BLE chip will sometimes send packets early (some internal
|
||||
// serial buffer timeout?) with incompete data.
|
||||
//
|
||||
// So read packets until you get newline.
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_recv_line (deepblu_cosmiq_device_t *device, unsigned char data[], size_t size, size_t *actual)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
size_t nbytes = 0;
|
||||
|
||||
while (1) {
|
||||
unsigned char buffer[20] = {0};
|
||||
size_t transferred = 0;
|
||||
|
||||
status = dc_iostream_read (device->iostream, buffer, sizeof(buffer), &transferred);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (device->base.context, "Failed to receive the reply packet.");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (transferred < 1) {
|
||||
ERROR (device->base.context, "Empty reply packet received.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Append the payload data to the output buffer. If the output
|
||||
// buffer is too small, the error is not reported immediately
|
||||
// but delayed until all packets have been received.
|
||||
if (nbytes < size) {
|
||||
size_t n = transferred;
|
||||
if (nbytes + n > size) {
|
||||
n = size - nbytes;
|
||||
}
|
||||
memcpy(data + nbytes, buffer, n);
|
||||
}
|
||||
nbytes += transferred;
|
||||
|
||||
// Last packet?
|
||||
if (buffer[transferred - 1] == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
// Verify the expected number of bytes.
|
||||
if (nbytes > size) {
|
||||
ERROR (device->base.context, "Unexpected number of bytes received (" DC_PRINTF_SIZE " " DC_PRINTF_SIZE ").", nbytes, size);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (actual)
|
||||
*actual = nbytes;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
//
|
||||
// Receive a reply packet
|
||||
//
|
||||
// The reply packet has the same format as the cmd packet we
|
||||
// send, except the first byte is '$' instead of '#'.
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_recv (deepblu_cosmiq_device_t *device, const unsigned char cmd, unsigned char data[], size_t size, size_t *actual)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
unsigned char packet[1 + 2 * (3 + MAX_DATA) + 1] = {0};
|
||||
|
||||
size_t transferred = 0;
|
||||
status = deepblu_cosmiq_recv_line (device, packet, sizeof(packet), &transferred);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (transferred < 8 || (transferred % 2) != 0) {
|
||||
ERROR (device->base.context, "Unexpected packet length (" DC_PRINTF_SIZE ").", transferred);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (packet[0] != '$' || packet[transferred - 1] != '\n') {
|
||||
ERROR (device->base.context, "Unexpected packet start/end byte.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
size_t length = transferred - 2;
|
||||
|
||||
unsigned char raw[3 + MAX_DATA] = {0};
|
||||
if (array_convert_hex2bin (packet + 1, length, raw, length / 2) != 0) {
|
||||
ERROR (device->base.context, "Unexpected packet data.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
length /= 2;
|
||||
|
||||
HEXDUMP (device->base.context, DC_LOGLEVEL_DEBUG, "rcv", raw, length);
|
||||
|
||||
unsigned char rsp = raw[0];
|
||||
if (rsp != cmd) {
|
||||
ERROR (device->base.context, "Unexpected packet command byte (%02x)", rsp);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
unsigned int n = raw[2];
|
||||
if ((n % 2) != 0 || n != transferred - 8) {
|
||||
ERROR (device->base.context, "Unexpected packet length (%u)", n);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
unsigned char csum = checksum_add_uint8 (raw, length, 0);
|
||||
if (csum != 0) {
|
||||
ERROR (device->base.context, "Unexpected packet checksum (%02x).", csum);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
length -= 3;
|
||||
|
||||
if (length > size) {
|
||||
ERROR (device->base.context, "Unexpected number of bytes received (" DC_PRINTF_SIZE " " DC_PRINTF_SIZE ").", length, size);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
memcpy (data, raw + 3, length);
|
||||
|
||||
if (actual)
|
||||
*actual = length;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_transfer (deepblu_cosmiq_device_t *device, const unsigned char cmd,
|
||||
const unsigned char input[], size_t isize,
|
||||
unsigned char output[], size_t osize)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
|
||||
status = deepblu_cosmiq_send (device, cmd, input, isize);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
size_t transferred = 0;
|
||||
status = deepblu_cosmiq_recv (device, cmd, output, osize, &transferred);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (transferred != osize) {
|
||||
ERROR (device->base.context, "Unexpected number of bytes received (" DC_PRINTF_SIZE " " DC_PRINTF_SIZE ").", osize, transferred);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_recv_bulk (deepblu_cosmiq_device_t *device, dc_event_progress_t *progress, const unsigned char cmd, unsigned char data[], size_t size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
const unsigned int initial = progress ? progress->current : 0;
|
||||
|
||||
size_t nbytes = 0;
|
||||
while (nbytes < size) {
|
||||
size_t transferred = 0;
|
||||
status = deepblu_cosmiq_recv (device, cmd, data + nbytes, size - nbytes, &transferred);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
nbytes += transferred;
|
||||
|
||||
// Update and emit a progress event.
|
||||
if (progress) {
|
||||
progress->current = initial + STEP(nbytes, size);
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
|
||||
}
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
deepblu_cosmiq_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
deepblu_cosmiq_device_t *device = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
device = (deepblu_cosmiq_device_t *) dc_device_allocate (context, &deepblu_cosmiq_device_vtable);
|
||||
if (device == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
device->iostream = iostream;
|
||||
memset (device->fingerprint, 0, sizeof(device->fingerprint));
|
||||
|
||||
// Set the timeout for receiving data (1000ms).
|
||||
status = dc_iostream_set_timeout (device->iostream, 1000);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the timeout.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
dc_iostream_purge (device->iostream, DC_DIRECTION_ALL);
|
||||
|
||||
*out = (dc_device_t *) device;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free:
|
||||
dc_device_deallocate ((dc_device_t *) device);
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
|
||||
{
|
||||
deepblu_cosmiq_device_t *device = (deepblu_cosmiq_device_t *)abstract;
|
||||
|
||||
if (size && size != sizeof (device->fingerprint))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (size)
|
||||
memcpy (device->fingerprint, data, sizeof (device->fingerprint));
|
||||
else
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
deepblu_cosmiq_device_t *device = (deepblu_cosmiq_device_t *) abstract;
|
||||
const unsigned char zero = 0;
|
||||
|
||||
// Enable progress notifications.
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
// Read the firmware version.
|
||||
unsigned char fw[1] = {0};
|
||||
status = deepblu_cosmiq_transfer (device, CMD_SYSTEM_FW, &zero, 1, fw, sizeof(fw));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the firmware version.");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// Read the MAC address.
|
||||
unsigned char mac[6] = {0};
|
||||
status = deepblu_cosmiq_transfer (device, CMD_SYSTEM_MAC, &zero, 1, mac, sizeof(mac));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the MAC address.");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = 0;
|
||||
devinfo.firmware = fw[0] & 0x3F;
|
||||
devinfo.serial = array_uint32_le (mac);
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
unsigned char ndives = 0;
|
||||
status = deepblu_cosmiq_transfer (device, CMD_DIVE_COUNT, &zero, 1, &ndives, 1);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the number of dives.");
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current = (ndives == 0 ? 1 : 0) * NSTEPS;
|
||||
progress.maximum = (ndives + 1) * NSTEPS;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
if (ndives == 0) {
|
||||
status = DC_STATUS_SUCCESS;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
unsigned char *headers = malloc (ndives * SZ_HEADER);
|
||||
if (headers == NULL) {
|
||||
ERROR (abstract->context, "Failed to allocate memory.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_exit;
|
||||
}
|
||||
|
||||
unsigned int count = 0;
|
||||
for (unsigned int i = 0; i < ndives; ++i) {
|
||||
unsigned char number = i + 1;
|
||||
|
||||
unsigned char len = 0;
|
||||
status = deepblu_cosmiq_transfer (device, CMD_DIVE_HEADER, &number, 1, &len, 1);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the dive header.");
|
||||
goto error_free_headers;
|
||||
}
|
||||
|
||||
if (len != SZ_HEADER) {
|
||||
status = DC_STATUS_PROTOCOL;
|
||||
goto error_free_headers;
|
||||
}
|
||||
|
||||
status = deepblu_cosmiq_recv_bulk (device, NULL, CMD_DIVE_HEADER_DATA, headers + i * SZ_HEADER, SZ_HEADER);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the dive header.");
|
||||
goto error_free_headers;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current = STEP(i + 1, ndives);
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
if (memcmp (headers + i * SZ_HEADER + FP_OFFSET, device->fingerprint, sizeof (device->fingerprint)) == 0)
|
||||
break;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current = 1 * NSTEPS;
|
||||
progress.maximum = (count + 1) * NSTEPS;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
// Allocate memory for the dive.
|
||||
dc_buffer_t *dive = dc_buffer_new (4096);
|
||||
if (dive == NULL) {
|
||||
ERROR (abstract->context, "Failed to allocate memory.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free_headers;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
unsigned char number = i + 1;
|
||||
|
||||
unsigned char rsp_len[2] = {0};
|
||||
status = deepblu_cosmiq_transfer (device, CMD_DIVE_PROFILE, &number, 1, rsp_len, sizeof(rsp_len));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the dive profile.");
|
||||
goto error_free_dive;
|
||||
}
|
||||
|
||||
unsigned int len = array_uint16_be (rsp_len);
|
||||
|
||||
// Erase the buffer.
|
||||
dc_buffer_clear (dive);
|
||||
|
||||
// Allocate memory for the dive.
|
||||
if (!dc_buffer_resize (dive, len + SZ_HEADER)) {
|
||||
ERROR (abstract->context, "Failed to allocate memory.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free_dive;
|
||||
}
|
||||
|
||||
// Cache the pointer.
|
||||
unsigned char *data = dc_buffer_get_data (dive);
|
||||
|
||||
memcpy (data, headers + i * SZ_HEADER, SZ_HEADER);
|
||||
|
||||
status = deepblu_cosmiq_recv_bulk (device, &progress, CMD_DIVE_PROFILE_DATA, data + SZ_HEADER, len);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the dive profile.");
|
||||
goto error_free_dive;
|
||||
}
|
||||
|
||||
if (callback && !callback (data, len + SZ_HEADER, data + FP_OFFSET, FP_SIZE, userdata))
|
||||
break;
|
||||
}
|
||||
|
||||
error_free_dive:
|
||||
dc_buffer_free (dive);
|
||||
error_free_headers:
|
||||
free (headers);
|
||||
error_exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
deepblu_cosmiq_device_t *device = (deepblu_cosmiq_device_t *) abstract;
|
||||
|
||||
if (datetime->year < 2000) {
|
||||
ERROR (abstract->context, "Invalid date/time value specified.");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
const unsigned char cmd[6] = {
|
||||
dec2bcd(datetime->year - 2000),
|
||||
dec2bcd(datetime->month),
|
||||
dec2bcd(datetime->day),
|
||||
dec2bcd(datetime->hour),
|
||||
dec2bcd(datetime->minute),
|
||||
dec2bcd(datetime->second)};
|
||||
unsigned char rsp[1] = {0};
|
||||
status = deepblu_cosmiq_transfer (device, CMD_SET_DATETIME,
|
||||
cmd, sizeof(cmd), rsp, sizeof(rsp));
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
44
src/deepblu_cosmiq.h
Normal file
44
src/deepblu_cosmiq.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2018 Linus Torvalds
|
||||
* Copyright (C) 2022 Jef Driesen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef DEEPBLU_COSMIQ_H
|
||||
#define DEEPBLU_COSMIQ_H
|
||||
|
||||
#include <libdivecomputer/context.h>
|
||||
#include <libdivecomputer/iostream.h>
|
||||
#include <libdivecomputer/device.h>
|
||||
#include <libdivecomputer/parser.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
dc_status_t
|
||||
deepblu_cosmiq_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
deepblu_cosmiq_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* DEEPBLU_COSMIQ_H */
|
||||
211
src/deepblu_cosmiq_parser.c
Normal file
211
src/deepblu_cosmiq_parser.c
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2019 Linus Torvalds
|
||||
* Copyright (C) 2022 Jef Driesen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <libdivecomputer/units.h>
|
||||
|
||||
#include "deepblu_cosmiq.h"
|
||||
#include "context-private.h"
|
||||
#include "parser-private.h"
|
||||
#include "array.h"
|
||||
|
||||
#define SCUBA 2
|
||||
#define GAUGE 3
|
||||
#define FREEDIVE 4
|
||||
|
||||
#define SZ_HEADER 36
|
||||
#define SZ_SAMPLE 4
|
||||
|
||||
typedef struct deepblu_cosmiq_parser_t {
|
||||
dc_parser_t base;
|
||||
double hydrostatic;
|
||||
} deepblu_cosmiq_parser_t;
|
||||
|
||||
static dc_status_t deepblu_cosmiq_parser_set_density (dc_parser_t *abstract, double density);
|
||||
static dc_status_t deepblu_cosmiq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t deepblu_cosmiq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t deepblu_cosmiq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
|
||||
static const dc_parser_vtable_t deepblu_cosmiq_parser_vtable = {
|
||||
sizeof(deepblu_cosmiq_parser_t),
|
||||
DC_FAMILY_DEEPBLU_COSMIQ,
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
deepblu_cosmiq_parser_set_density, /* set_density */
|
||||
deepblu_cosmiq_parser_get_datetime, /* datetime */
|
||||
deepblu_cosmiq_parser_get_field, /* fields */
|
||||
deepblu_cosmiq_parser_samples_foreach, /* samples_foreach */
|
||||
NULL /* destroy */
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
deepblu_cosmiq_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
deepblu_cosmiq_parser_t *parser = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (deepblu_cosmiq_parser_t *) dc_parser_allocate (context, &deepblu_cosmiq_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
parser->hydrostatic = DEF_DENSITY_SALT * GRAVITY;
|
||||
|
||||
*out = (dc_parser_t *) parser;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_parser_set_density (dc_parser_t *abstract, double density)
|
||||
{
|
||||
deepblu_cosmiq_parser_t *parser = (deepblu_cosmiq_parser_t *) abstract;
|
||||
|
||||
parser->hydrostatic = density * GRAVITY;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
if (size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
if (datetime) {
|
||||
datetime->year = array_uint16_le(data + 6);
|
||||
datetime->day = data[8];
|
||||
datetime->month = data[9];
|
||||
datetime->minute = data[10];
|
||||
datetime->hour = data[11];
|
||||
datetime->second = 0;
|
||||
datetime->timezone = DC_TIMEZONE_NONE;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
|
||||
{
|
||||
deepblu_cosmiq_parser_t *parser = (deepblu_cosmiq_parser_t *) abstract;
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
|
||||
if (size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int mode = data[2];
|
||||
unsigned int atmospheric = array_uint16_le (data + 4) & 0x1FFF;
|
||||
|
||||
if (value) {
|
||||
switch (type) {
|
||||
case DC_FIELD_DIVETIME:
|
||||
if (mode == SCUBA || mode == GAUGE)
|
||||
*((unsigned int *) value) = array_uint16_le(data + 12) * 60;
|
||||
else
|
||||
*((unsigned int *) value) = array_uint16_le(data + 12);
|
||||
break;
|
||||
case DC_FIELD_MAXDEPTH:
|
||||
*((double *) value) = (signed int) (array_uint16_le (data + 22) - atmospheric) * (BAR / 1000.0) / parser->hydrostatic;
|
||||
break;
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
*((unsigned int *) value) = mode == SCUBA;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->oxygen = data[3] / 100.0;
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
break;
|
||||
case DC_FIELD_DIVEMODE:
|
||||
switch (mode) {
|
||||
case SCUBA:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_OC;
|
||||
break;
|
||||
case GAUGE:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_GAUGE;
|
||||
break;
|
||||
case FREEDIVE:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_FREEDIVE;
|
||||
break;
|
||||
default:
|
||||
ERROR (abstract->context, "Unknown activity type '%02x'", mode);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
*((double *) value) = atmospheric / 1000.0;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
deepblu_cosmiq_parser_t *parser = (deepblu_cosmiq_parser_t *) abstract;
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
if (size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int interval = data[26];
|
||||
unsigned int atmospheric = array_uint16_le (data + 4) & 0x1FFF;
|
||||
|
||||
unsigned int time = 0;
|
||||
unsigned int offset = SZ_HEADER;
|
||||
while (offset + SZ_SAMPLE <= size) {
|
||||
dc_sample_value_t sample = {0};
|
||||
unsigned int temperature = array_uint16_le(data + offset + 0);
|
||||
unsigned int depth = array_uint16_le(data + offset + 2);
|
||||
offset += SZ_SAMPLE;
|
||||
|
||||
time += interval;
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
sample.depth = (signed int) (depth - atmospheric) * (BAR / 1000.0) / parser->hydrostatic;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
@ -1,278 +0,0 @@
|
||||
/*
|
||||
* Deeplu Cosmiq+ parsing
|
||||
*
|
||||
* Copyright (C) 2019 Linus Torvalds
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "deepblu.h"
|
||||
#include "context-private.h"
|
||||
#include "parser-private.h"
|
||||
#include "array.h"
|
||||
#include "field-cache.h"
|
||||
|
||||
#define C_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
|
||||
|
||||
#define MAXFIELDS 128
|
||||
|
||||
struct msg_desc;
|
||||
|
||||
typedef struct deepblu_parser_t {
|
||||
dc_parser_t base;
|
||||
|
||||
dc_sample_callback_t callback;
|
||||
void *userdata;
|
||||
|
||||
// 20 sec for scuba, 1 sec for freedives
|
||||
int sample_interval;
|
||||
|
||||
// Common fields
|
||||
struct dc_field_cache cache;
|
||||
} deepblu_parser_t;
|
||||
|
||||
static dc_status_t deepblu_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t deepblu_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t deepblu_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t deepblu_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
|
||||
static const dc_parser_vtable_t deepblu_parser_vtable = {
|
||||
sizeof(deepblu_parser_t),
|
||||
DC_FAMILY_DEEPBLU,
|
||||
deepblu_parser_set_data, /* set_data */
|
||||
deepblu_parser_get_datetime, /* datetime */
|
||||
deepblu_parser_get_field, /* fields */
|
||||
deepblu_parser_samples_foreach, /* samples_foreach */
|
||||
NULL /* destroy */
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
deepblu_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
{
|
||||
deepblu_parser_t *parser = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (deepblu_parser_t *) dc_parser_allocate (context, &deepblu_parser_vtable);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
*out = (dc_parser_t *) parser;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static double
|
||||
pressure_to_depth(unsigned int mbar)
|
||||
{
|
||||
// Specific weight of seawater (millibar to cm)
|
||||
const double specific_weight = 1.024 * 0.980665;
|
||||
|
||||
// Absolute pressure, subtract surface pressure
|
||||
if (mbar < 1013)
|
||||
return 0.0;
|
||||
mbar -= 1013;
|
||||
return mbar / specific_weight / 100.0;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
deepblu_parser_t *deepblu = (deepblu_parser_t *) abstract;
|
||||
const unsigned char *hdr = data;
|
||||
const unsigned char *profile = data + 256;
|
||||
unsigned int divetime, maxpressure;
|
||||
dc_gasmix_t gasmix = {0, };
|
||||
|
||||
if (size < 256)
|
||||
return DC_STATUS_IO;
|
||||
|
||||
deepblu->callback = NULL;
|
||||
deepblu->userdata = NULL;
|
||||
memset(&deepblu->cache, 0, sizeof(deepblu->cache));
|
||||
|
||||
// LE16 at 0 is 'dive number'
|
||||
|
||||
// LE16 at 12 is the dive time
|
||||
// It's in seconds for freedives, minutes for scuba/gauge
|
||||
divetime = hdr[12] + 256*hdr[13];
|
||||
|
||||
// Byte at 2 is 'activity type' (2 = scuba, 3 = gauge, 4 = freedive)
|
||||
// Byte at 3 is O2 percentage
|
||||
switch (data[2]) {
|
||||
case 2:
|
||||
// SCUBA - divetime in minutes
|
||||
divetime *= 60;
|
||||
gasmix.oxygen = data[3] / 100.0;
|
||||
DC_ASSIGN_IDX(deepblu->cache, GASMIX, 0, gasmix);
|
||||
DC_ASSIGN_FIELD(deepblu->cache, GASMIX_COUNT, 1);
|
||||
DC_ASSIGN_FIELD(deepblu->cache, DIVEMODE, DC_DIVEMODE_OC);
|
||||
break;
|
||||
case 3:
|
||||
// GAUGE - divetime in minutes
|
||||
divetime *= 60;
|
||||
DC_ASSIGN_FIELD(deepblu->cache, DIVEMODE, DC_DIVEMODE_GAUGE);
|
||||
break;
|
||||
case 4:
|
||||
// FREEDIVE - divetime in seconds
|
||||
DC_ASSIGN_FIELD(deepblu->cache, DIVEMODE, DC_DIVEMODE_FREEDIVE);
|
||||
deepblu->sample_interval = 1;
|
||||
break;
|
||||
default:
|
||||
ERROR (abstract->context, "Deepblu: unknown activity type '%02x'", data[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
// Seems to be fixed at 20s for scuba, 1s for freedive
|
||||
deepblu->sample_interval = hdr[26];
|
||||
|
||||
maxpressure = hdr[22] + 256*hdr[23]; // Maxpressure in millibar
|
||||
|
||||
DC_ASSIGN_FIELD(deepblu->cache, DIVETIME, divetime);
|
||||
DC_ASSIGN_FIELD(deepblu->cache, MAXDEPTH, pressure_to_depth(maxpressure));
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// The layout of the header in the 'data' is
|
||||
// 0: LE16 dive number
|
||||
// 2: dive type byte?
|
||||
// 3: O2 percentage byte
|
||||
// 4: unknown
|
||||
// 5: unknown
|
||||
// 6: LE16 year
|
||||
// 8: day of month
|
||||
// 9: month
|
||||
// 10: minute
|
||||
// 11: hour
|
||||
// 12: LE16 dive time
|
||||
// 14: LE16 ??
|
||||
// 16: LE16 surface pressure?
|
||||
// 18: LE16 ??
|
||||
// 20: LE16 ??
|
||||
// 22: LE16 max depth pressure
|
||||
// 24: LE16 water temp
|
||||
// 26: LE16 ??
|
||||
// 28: LE16 ??
|
||||
// 30: LE16 ??
|
||||
// 32: LE16 ??
|
||||
// 34: LE16 ??
|
||||
static dc_status_t
|
||||
deepblu_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
deepblu_parser_t *deepblu = (deepblu_parser_t *) abstract;
|
||||
const unsigned char *data = deepblu->base.data;
|
||||
int len = deepblu->base.size;
|
||||
|
||||
if (len < 256)
|
||||
return DC_STATUS_IO;
|
||||
datetime->year = data[6] + (data[7] << 8);
|
||||
datetime->day = data[8];
|
||||
datetime->month = data[9];
|
||||
datetime->minute = data[10];
|
||||
datetime->hour = data[11];
|
||||
datetime->second = 0;
|
||||
datetime->timezone = DC_TIMEZONE_NONE;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
|
||||
{
|
||||
deepblu_parser_t *deepblu = (deepblu_parser_t *) abstract;
|
||||
|
||||
if (!value)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
/* This whole sequence should be standardized */
|
||||
if (!(deepblu->cache.initialized & (1 << type)))
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
|
||||
switch (type) {
|
||||
case DC_FIELD_DIVETIME:
|
||||
return DC_FIELD_VALUE(deepblu->cache, value, DIVETIME);
|
||||
case DC_FIELD_MAXDEPTH:
|
||||
return DC_FIELD_VALUE(deepblu->cache, value, MAXDEPTH);
|
||||
case DC_FIELD_AVGDEPTH:
|
||||
return DC_FIELD_VALUE(deepblu->cache, value, AVGDEPTH);
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
case DC_FIELD_TANK_COUNT:
|
||||
return DC_FIELD_VALUE(deepblu->cache, value, GASMIX_COUNT);
|
||||
case DC_FIELD_GASMIX:
|
||||
if (flags >= MAXGASES)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
return DC_FIELD_INDEX(deepblu->cache, value, GASMIX, flags);
|
||||
case DC_FIELD_SALINITY:
|
||||
return DC_FIELD_VALUE(deepblu->cache, value, SALINITY);
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
return DC_FIELD_VALUE(deepblu->cache, value, ATMOSPHERIC);
|
||||
case DC_FIELD_DIVEMODE:
|
||||
return DC_FIELD_VALUE(deepblu->cache, value, DIVEMODE);
|
||||
case DC_FIELD_TANK:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
case DC_FIELD_STRING:
|
||||
return dc_field_get_string(&deepblu->cache, flags, (dc_field_string_t *)value);
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
deepblu_parser_t *deepblu = (deepblu_parser_t *) abstract;
|
||||
const unsigned char *data = deepblu->base.data;
|
||||
int len = deepblu->base.size, i;
|
||||
|
||||
deepblu->callback = callback;
|
||||
deepblu->userdata = userdata;
|
||||
|
||||
// Skip the header information
|
||||
if (len < 256)
|
||||
return DC_STATUS_IO;
|
||||
data += 256;
|
||||
len -= 256;
|
||||
|
||||
// The rest should be samples every 20s with temperature and depth
|
||||
for (i = 0; i < len/4; i++) {
|
||||
dc_sample_value_t sample = {0};
|
||||
unsigned int temp = data[0]+256*data[1];
|
||||
unsigned int pressure = data[2]+256*data[3];
|
||||
|
||||
data += 4;
|
||||
sample.time = (i+1)*deepblu->sample_interval;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
|
||||
sample.depth = pressure_to_depth(pressure);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
|
||||
sample.temperature = temp / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
516
src/deepsix_excursion.c
Normal file
516
src/deepsix_excursion.c
Normal file
@ -0,0 +1,516 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2021 Ryan Gardner, Jef Driesen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "deepsix_excursion.h"
|
||||
#include "context-private.h"
|
||||
#include "device-private.h"
|
||||
#include "platform.h"
|
||||
#include "checksum.h"
|
||||
#include "array.h"
|
||||
|
||||
#define MAXPACKET 255
|
||||
|
||||
#define HEADERSIZE_MIN 128
|
||||
#define HEADERSIZE_V0 156
|
||||
|
||||
#define NSTEPS 1000
|
||||
#define STEP(i,n) (NSTEPS * (i) / (n))
|
||||
|
||||
#define FP_SIZE 6
|
||||
#define FP_OFFSET 12
|
||||
|
||||
#define DIR_WRITE 0x00
|
||||
#define DIR_READ 0x01
|
||||
|
||||
#define GRP_INFO 0xA0
|
||||
#define CMD_INFO_HARDWARE 0x01
|
||||
#define CMD_INFO_SOFTWARE 0x02
|
||||
#define CMD_INFO_SERIAL 0x03
|
||||
#define CMD_INFO_LASTDIVE 0x04
|
||||
|
||||
#define GRP_SETTINGS 0xB0
|
||||
#define CMD_SETTINGS_DATE 0x01
|
||||
#define CMD_SETTINGS_TIME 0x03
|
||||
#define CMD_SETTINGS_STORE 0x27
|
||||
#define CMD_SETTINGS_LOAD 0x28
|
||||
|
||||
#define GRP_DIVE 0xC0
|
||||
#define CMD_DIVE_HEADER 0x02
|
||||
#define CMD_DIVE_PROFILE 0x03
|
||||
#define CMD_DIVE_COUNT 0x05
|
||||
#define CMD_DIVE_INDEX_LAST 0x06
|
||||
#define CMD_DIVE_INDEX_FIRST 0x07
|
||||
#define CMD_DIVE_INDEX_PREVIOUS 0x08
|
||||
#define CMD_DIVE_INDEX_NEXT 0x09
|
||||
|
||||
typedef struct deepsix_excursion_device_t {
|
||||
dc_device_t base;
|
||||
dc_iostream_t *iostream;
|
||||
unsigned char fingerprint[FP_SIZE];
|
||||
} deepsix_excursion_device_t;
|
||||
|
||||
static dc_status_t deepsix_excursion_device_set_fingerprint (dc_device_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t deepsix_excursion_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
||||
static dc_status_t deepsix_excursion_device_timesync(dc_device_t *abstract, const dc_datetime_t *datetime);
|
||||
|
||||
static const dc_device_vtable_t deepsix_excursion_device_vtable = {
|
||||
sizeof(deepsix_excursion_device_t),
|
||||
DC_FAMILY_DEEPSIX_EXCURSION,
|
||||
deepsix_excursion_device_set_fingerprint, /* set_fingerprint */
|
||||
NULL, /* read */
|
||||
NULL, /* write */
|
||||
NULL, /* dump */
|
||||
deepsix_excursion_device_foreach, /* foreach */
|
||||
deepsix_excursion_device_timesync, /* timesync */
|
||||
NULL, /* close */
|
||||
};
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_send (deepsix_excursion_device_t *device, unsigned char grp, unsigned char cmd, unsigned char dir, const unsigned char data[], unsigned int size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
unsigned char packet[4 + MAXPACKET + 1];
|
||||
|
||||
if (device_is_cancelled (abstract))
|
||||
return DC_STATUS_CANCELLED;
|
||||
|
||||
if (size > MAXPACKET)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Setup the data packet
|
||||
packet[0] = grp;
|
||||
packet[1] = cmd;
|
||||
packet[2] = dir;
|
||||
packet[3] = size;
|
||||
if (size) {
|
||||
memcpy(packet + 4, data, size);
|
||||
}
|
||||
packet[size + 4] = checksum_add_uint8 (packet, size + 4, 0) ^ 0xFF;
|
||||
|
||||
// Send the data packet.
|
||||
status = dc_iostream_write (device->iostream, packet, 4 + size + 1, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_recv (deepsix_excursion_device_t *device, unsigned char grp, unsigned char cmd, unsigned char dir, unsigned char data[], unsigned int size, unsigned int *actual)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
unsigned char packet[4 + MAXPACKET + 1];
|
||||
size_t transferred = 0;
|
||||
|
||||
// Read the packet header, payload and checksum.
|
||||
status = dc_iostream_read (device->iostream, packet, sizeof(packet), &transferred);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the packet.");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (transferred < 4) {
|
||||
ERROR (abstract->context, "Packet header too short ("DC_PRINTF_SIZE").", transferred);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Verify the packet header.
|
||||
if (packet[0] != grp || packet[1] != cmd || packet[2] != dir) {
|
||||
ERROR (device->base.context, "Unexpected packet header.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
unsigned int len = packet[3];
|
||||
if (len > MAXPACKET) {
|
||||
ERROR (abstract->context, "Packet header length too large (%u).", len);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (transferred < 4 + len + 1) {
|
||||
ERROR (abstract->context, "Packet data too short ("DC_PRINTF_SIZE").", transferred);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Verify the checksum.
|
||||
unsigned char csum = checksum_add_uint8 (packet, len + 4, 0) ^ 0xFF;
|
||||
if (packet[len + 4] != csum) {
|
||||
ERROR (abstract->context, "Unexpected packet checksum (%02x)", csum);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (len > size) {
|
||||
ERROR (abstract->context, "Unexpected packet length (%u).", len);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
memcpy(data, packet + 4, len);
|
||||
}
|
||||
|
||||
if (actual)
|
||||
*actual = len;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_transfer (deepsix_excursion_device_t *device, unsigned char grp, unsigned char cmd, unsigned char dir, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int *actual)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
|
||||
status = deepsix_excursion_send (device, grp, cmd, dir, command, csize);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = deepsix_excursion_recv (device, grp + 1, cmd, dir, answer, asize, actual);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
deepsix_excursion_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
deepsix_excursion_device_t *device = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
device = (deepsix_excursion_device_t *) dc_device_allocate (context, &deepsix_excursion_device_vtable);
|
||||
if (device == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
device->iostream = iostream;
|
||||
memset(device->fingerprint, 0, sizeof(device->fingerprint));
|
||||
|
||||
// Set the serial communication protocol (115200 8N1).
|
||||
status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the terminal attributes.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Set the timeout for receiving data (3000ms).
|
||||
status = dc_iostream_set_timeout (device->iostream, 3000);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the timeout.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Make sure everything is in a sane state.
|
||||
dc_iostream_sleep (device->iostream, 300);
|
||||
dc_iostream_purge (device->iostream, DC_DIRECTION_ALL);
|
||||
|
||||
*out = (dc_device_t *) device;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free:
|
||||
dc_device_deallocate ((dc_device_t *) device);
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_device_set_fingerprint (dc_device_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
deepsix_excursion_device_t *device = (deepsix_excursion_device_t *)abstract;
|
||||
|
||||
if (size && size != sizeof (device->fingerprint))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (size)
|
||||
memcpy (device->fingerprint, data, sizeof (device->fingerprint));
|
||||
else
|
||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
deepsix_excursion_device_t *device = (deepsix_excursion_device_t *) abstract;
|
||||
|
||||
// Enable progress notifications.
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
// Load the settings into memory.
|
||||
status = deepsix_excursion_transfer (device, GRP_SETTINGS, CMD_SETTINGS_LOAD, DIR_WRITE, NULL, 0, NULL, 0, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to load the settings.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Read the hardware version.
|
||||
unsigned char rsp_hardware[6] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_INFO, CMD_INFO_HARDWARE, DIR_READ, NULL, 0, rsp_hardware, sizeof(rsp_hardware), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the hardware version.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Read the software version.
|
||||
unsigned char rsp_software[6] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_INFO, CMD_INFO_SOFTWARE, DIR_READ, NULL, 0, rsp_software, sizeof(rsp_software), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the software version.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Read the serial number
|
||||
unsigned char rsp_serial[12] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_INFO, CMD_INFO_SERIAL, DIR_READ, NULL, 0, rsp_serial, sizeof(rsp_serial), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the serial number.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = 0;
|
||||
devinfo.firmware = array_uint16_be (rsp_software + 4);
|
||||
devinfo.serial = array_convert_str2num (rsp_serial + 3, sizeof(rsp_serial) - 3);
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
// Firmware version 6+ uses the new commands.
|
||||
unsigned int fw6 = memcmp(rsp_software, "D01", 3) == 0 && rsp_software[4] >= '6';
|
||||
|
||||
unsigned int ndives = 0, last = 0;
|
||||
if (fw6) {
|
||||
// Read the number of dives.
|
||||
unsigned char rsp_ndives[2] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_DIVE, CMD_DIVE_COUNT, DIR_READ, NULL, 0, rsp_ndives, sizeof(rsp_ndives), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the number of dives");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Read the index of the last dive.
|
||||
unsigned char rsp_last[4] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_DIVE, CMD_DIVE_INDEX_LAST, DIR_READ, NULL, 0, rsp_last, sizeof(rsp_last), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the last dive index.");
|
||||
return status;
|
||||
}
|
||||
|
||||
ndives = array_uint16_le (rsp_ndives);
|
||||
last = array_uint16_le (rsp_last);
|
||||
} else {
|
||||
// Read the index of the last dive.
|
||||
const unsigned char cmd_last[2] = {0};
|
||||
unsigned char rsp_last[2] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_INFO, CMD_INFO_LASTDIVE, DIR_READ, cmd_last, sizeof(cmd_last), rsp_last, sizeof(rsp_last), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the last dive index.");
|
||||
return status;
|
||||
}
|
||||
|
||||
ndives = last = array_uint16_le (rsp_last);
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current = 1 * NSTEPS;
|
||||
progress.maximum = (ndives + 1) * NSTEPS;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
dc_buffer_t *buffer = dc_buffer_new(0);
|
||||
if (buffer == NULL) {
|
||||
ERROR (abstract->context, "Insufficient buffer space available.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
unsigned int number = last;
|
||||
for (unsigned int i = 0; i < ndives; ++i) {
|
||||
if (fw6) {
|
||||
if (i > 0) {
|
||||
const unsigned char cmd_previous[] = {
|
||||
(number ) & 0xFF,
|
||||
(number >> 8) & 0xFF,
|
||||
(number >> 16) & 0xFF,
|
||||
(number >> 24) & 0xFF};
|
||||
unsigned char rsp_previous[4] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_DIVE, CMD_DIVE_INDEX_PREVIOUS, DIR_READ,
|
||||
cmd_previous, sizeof(cmd_previous), rsp_previous, sizeof(rsp_previous), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the previous dive index");
|
||||
return status;
|
||||
}
|
||||
number = array_uint32_le (rsp_previous);
|
||||
}
|
||||
} else {
|
||||
number = ndives - i;
|
||||
}
|
||||
|
||||
unsigned int headersize = 0;
|
||||
const unsigned char cmd_header[] = {
|
||||
(number ) & 0xFF,
|
||||
(number >> 8) & 0xFF};
|
||||
unsigned char rsp_header[MAXPACKET] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_DIVE, CMD_DIVE_HEADER, DIR_READ,
|
||||
cmd_header, sizeof(cmd_header), rsp_header, sizeof(rsp_header), &headersize);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the dive header.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
if (headersize < HEADERSIZE_MIN || headersize != (fw6 ? rsp_header[2] : HEADERSIZE_V0)) {
|
||||
ERROR (abstract->context, "Unexpected size of the dive header (%u).", headersize);
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
if (memcmp(rsp_header + FP_OFFSET, device->fingerprint, sizeof(device->fingerprint)) == 0)
|
||||
break;
|
||||
|
||||
unsigned int length = array_uint32_le (rsp_header + 8);
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current = (i + 1) * NSTEPS + STEP(headersize, headersize + length);
|
||||
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
dc_buffer_clear(buffer);
|
||||
dc_buffer_reserve(buffer, headersize + length);
|
||||
|
||||
if (!dc_buffer_append(buffer, rsp_header, headersize)) {
|
||||
ERROR (abstract->context, "Insufficient buffer space available.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
unsigned offset = 0;
|
||||
while (offset < length) {
|
||||
unsigned int len = 0;
|
||||
const unsigned char cmd_profile[] = {
|
||||
(number ) & 0xFF,
|
||||
(number >> 8) & 0xFF,
|
||||
(offset ) & 0xFF,
|
||||
(offset >> 8) & 0xFF,
|
||||
(offset >> 16) & 0xFF,
|
||||
(offset >> 24) & 0xFF};
|
||||
unsigned char rsp_profile[MAXPACKET] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_DIVE, CMD_DIVE_PROFILE, DIR_READ,
|
||||
cmd_profile, sizeof(cmd_profile), rsp_profile, sizeof(rsp_profile), &len);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the dive profile.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Remove padding from the last packet.
|
||||
unsigned int n = len;
|
||||
if (offset + n > length) {
|
||||
n = length - offset;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current = (i + 1) * NSTEPS + STEP(headersize + offset + n, headersize + length);
|
||||
device_event_emit(abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
if (!dc_buffer_append(buffer, rsp_profile, n)) {
|
||||
ERROR (abstract->context, "Insufficient buffer space available.");
|
||||
status = DC_STATUS_NOMEMORY;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
offset += n;
|
||||
}
|
||||
|
||||
unsigned char *data = dc_buffer_get_data(buffer);
|
||||
unsigned int size = dc_buffer_get_size(buffer);
|
||||
if (callback && !callback (data, size, data + FP_OFFSET, sizeof(device->fingerprint), userdata)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
error_free:
|
||||
dc_buffer_free(buffer);
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
deepsix_excursion_device_t *device = (deepsix_excursion_device_t *) abstract;
|
||||
|
||||
if (datetime->year < 2000) {
|
||||
ERROR (abstract->context, "Invalid date/time value specified.");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
const unsigned char cmd_date[] = {
|
||||
datetime->year - 2000,
|
||||
datetime->month,
|
||||
datetime->day};
|
||||
|
||||
const unsigned char cmd_time[] = {
|
||||
datetime->hour,
|
||||
datetime->minute,
|
||||
datetime->second};
|
||||
|
||||
const unsigned char cmd_store[] = {0x00};
|
||||
|
||||
unsigned char rsp_date[sizeof(cmd_date)] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_SETTINGS, CMD_SETTINGS_DATE, DIR_WRITE, cmd_date, sizeof(cmd_date), rsp_date, sizeof(rsp_date), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to set the date.");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (memcmp(rsp_date, cmd_date, sizeof(cmd_date)) != 0) {
|
||||
ERROR (abstract->context, "Failed to verify the date.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
unsigned char rsp_time[sizeof(cmd_time)] = {0};
|
||||
status = deepsix_excursion_transfer (device, GRP_SETTINGS, CMD_SETTINGS_TIME, DIR_WRITE, cmd_time, sizeof(cmd_time), rsp_time, sizeof(rsp_time), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to set the time.");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (memcmp(rsp_time, cmd_time, sizeof(cmd_time)) != 0) {
|
||||
ERROR (abstract->context, "Failed to verify the time.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
status = deepsix_excursion_transfer (device, GRP_SETTINGS, CMD_SETTINGS_STORE, DIR_WRITE, cmd_store, sizeof(cmd_store), NULL, 0, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to store the settings.");
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
43
src/deepsix_excursion.h
Normal file
43
src/deepsix_excursion.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2021 Ryan Gardner, Jef Driesen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
#ifndef DEEPSIX_EXCURSION_H
|
||||
#define DEEPSIX_EXCURSION_H
|
||||
|
||||
#include <libdivecomputer/context.h>
|
||||
#include <libdivecomputer/iostream.h>
|
||||
#include <libdivecomputer/device.h>
|
||||
#include <libdivecomputer/parser.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
dc_status_t
|
||||
deepsix_excursion_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
deepsix_excursion_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* DEEPSIX_EXCURSION_H */
|
||||
768
src/deepsix_excursion_parser.c
Normal file
768
src/deepsix_excursion_parser.c
Normal file
@ -0,0 +1,768 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2021 Ryan Gardner, Jef Driesen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libdivecomputer/units.h>
|
||||
|
||||
#include "deepsix_excursion.h"
|
||||
#include "context-private.h"
|
||||
#include "parser-private.h"
|
||||
#include "array.h"
|
||||
|
||||
#define HEADERSIZE_MIN 128
|
||||
|
||||
#define MAX_SAMPLES 7
|
||||
#define MAX_EVENTS 7
|
||||
#define MAX_GASMIXES 20
|
||||
|
||||
#define ALARM 0x0001
|
||||
#define TEMPERATURE 0x0002
|
||||
#define DECO 0x0003
|
||||
#define CEILING 0x0004
|
||||
#define CNS 0x0005
|
||||
|
||||
#define SAMPLE_TEMPERATURE 0
|
||||
#define SAMPLE_DECO_NDL 1
|
||||
#define SAMPLE_CNS 2
|
||||
|
||||
#define EVENT_CHANGE_GAS 7
|
||||
#define EVENT_ALARMS 8
|
||||
#define EVENT_CHANGE_SETPOINT 9
|
||||
#define EVENT_SAMPLES_MISSED 10
|
||||
#define EVENT_RESERVED 15
|
||||
|
||||
#define ALARM_ASCENTRATE 0
|
||||
#define ALARM_CEILING 1
|
||||
#define ALARM_PO2 2
|
||||
#define ALARM_MAXDEPTH 3
|
||||
#define ALARM_DIVETIME 4
|
||||
#define ALARM_CNS 5
|
||||
|
||||
#define DECOSTOP 0x02
|
||||
#define SAFETYSTOP 0x04
|
||||
|
||||
#define DENSITY 1024
|
||||
|
||||
#define UNDEFINED 0xFFFFFFFF
|
||||
|
||||
#define FWVERSION(major,minor) ( \
|
||||
((((major) + '0') & 0xFF) << 8) | \
|
||||
((minor) & 0xFF))
|
||||
|
||||
typedef struct deepsix_excursion_layout_t {
|
||||
unsigned int headersize;
|
||||
unsigned int version;
|
||||
unsigned int divemode;
|
||||
unsigned int samplerate;
|
||||
unsigned int salinity;
|
||||
unsigned int datetime;
|
||||
unsigned int divetime;
|
||||
unsigned int maxdepth;
|
||||
unsigned int temperature_min;
|
||||
unsigned int avgdepth;
|
||||
unsigned int firmware;
|
||||
unsigned int temperature_surf;
|
||||
unsigned int atmospheric;
|
||||
unsigned int gf;
|
||||
} deepsix_excursion_layout_t;
|
||||
|
||||
typedef struct deepsix_excursion_gasmix_t {
|
||||
unsigned int id;
|
||||
unsigned int oxygen;
|
||||
unsigned int helium;
|
||||
} deepsix_excursion_gasmix_t;
|
||||
|
||||
typedef struct deepsix_excursion_sample_info_t {
|
||||
unsigned int type;
|
||||
unsigned int divisor;
|
||||
unsigned int size;
|
||||
} deepsix_excursion_sample_info_t;
|
||||
|
||||
typedef struct deepsix_excursion_event_info_t {
|
||||
unsigned int type;
|
||||
unsigned int size;
|
||||
} deepsix_excursion_event_info_t;
|
||||
|
||||
typedef struct deepsix_excursion_parser_t {
|
||||
dc_parser_t base;
|
||||
unsigned int cached;
|
||||
unsigned int ngasmixes;
|
||||
deepsix_excursion_gasmix_t gasmix[MAX_GASMIXES];
|
||||
} deepsix_excursion_parser_t;
|
||||
|
||||
static dc_status_t deepsix_excursion_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t deepsix_excursion_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t deepsix_excursion_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
static dc_status_t deepsix_excursion_parser_samples_foreach_v0 (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
static dc_status_t deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
|
||||
static const dc_parser_vtable_t deepsix_parser_vtable = {
|
||||
sizeof(deepsix_excursion_parser_t),
|
||||
DC_FAMILY_DEEPSIX_EXCURSION,
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
deepsix_excursion_parser_get_datetime, /* datetime */
|
||||
deepsix_excursion_parser_get_field, /* fields */
|
||||
deepsix_excursion_parser_samples_foreach, /* samples_foreach */
|
||||
NULL /* destroy */
|
||||
};
|
||||
|
||||
static const deepsix_excursion_layout_t deepsix_excursion_layout_v0 = {
|
||||
156,/* headersize */
|
||||
UNDEFINED, /* version */
|
||||
4, /* divemode */
|
||||
24, /* samplerate */
|
||||
UNDEFINED, /* salinity */
|
||||
12, /* datetime */
|
||||
20, /* divetime */
|
||||
28, /* maxdepth */
|
||||
32, /* temperature_min */
|
||||
UNDEFINED, /* avgdepth */
|
||||
48, /* firmware */
|
||||
UNDEFINED, /* temperature_surf */
|
||||
56, /* atmospheric */
|
||||
UNDEFINED, /* gf */
|
||||
};
|
||||
|
||||
static const deepsix_excursion_layout_t deepsix_excursion_layout_v1 = {
|
||||
129,/* headersize */
|
||||
3, /* version */
|
||||
4, /* divemode */
|
||||
5, /* samplerate */
|
||||
7, /* salinity */
|
||||
12, /* datetime */
|
||||
19, /* divetime */
|
||||
29, /* maxdepth */
|
||||
31, /* temperature_min */
|
||||
33, /* avgdepth */
|
||||
35, /* firmware */
|
||||
43, /* temperature_surf */
|
||||
45, /* atmospheric */
|
||||
127, /* gf */
|
||||
};
|
||||
|
||||
static double
|
||||
pressure_to_depth(unsigned int depth, unsigned int atmospheric, unsigned int density)
|
||||
{
|
||||
return ((signed int)(depth - atmospheric)) * (BAR / 1000.0) / (density * GRAVITY);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
deepsix_excursion_find_gasmix(deepsix_excursion_parser_t *parser, unsigned int o2, unsigned int he, unsigned int id)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
while (i < parser->ngasmixes) {
|
||||
if (o2 == parser->gasmix[i].oxygen && he == parser->gasmix[i].helium && id == parser->gasmix[i].id)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
deepsix_excursion_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
deepsix_excursion_parser_t *parser = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (deepsix_excursion_parser_t *) dc_parser_allocate (context, &deepsix_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Set the default values.
|
||||
parser->cached = 0;
|
||||
parser->ngasmixes = 0;
|
||||
for (unsigned int i = 0; i < MAX_GASMIXES; ++i) {
|
||||
parser->gasmix[i].id = 0;
|
||||
parser->gasmix[i].oxygen = 0;
|
||||
parser->gasmix[i].helium = 0;
|
||||
}
|
||||
|
||||
*out = (dc_parser_t *) parser;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
if (size < HEADERSIZE_MIN)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int version = data[3];
|
||||
const deepsix_excursion_layout_t *layout = version == 0 ?
|
||||
&deepsix_excursion_layout_v0 : &deepsix_excursion_layout_v1;
|
||||
|
||||
if (size < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int firmware = array_uint16_be (data + layout->firmware + 4);
|
||||
|
||||
const unsigned char *p = data + layout->datetime;
|
||||
|
||||
if (datetime) {
|
||||
datetime->year = p[0] + 2000;
|
||||
datetime->month = p[1];
|
||||
datetime->day = p[2];
|
||||
datetime->hour = p[3];
|
||||
datetime->minute = p[4];
|
||||
datetime->second = p[5];
|
||||
|
||||
if (version == 0) {
|
||||
if (firmware >= FWVERSION(5, 'B')) {
|
||||
datetime->timezone = (p[6] - 12) * 3600;
|
||||
} else {
|
||||
datetime->timezone = DC_TIMEZONE_NONE;
|
||||
}
|
||||
} else {
|
||||
datetime->timezone = ((signed char) p[6]) * 900;
|
||||
}
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
|
||||
{
|
||||
deepsix_excursion_parser_t *parser = (deepsix_excursion_parser_t *) abstract;
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
dc_salinity_t *water = (dc_salinity_t *) value;
|
||||
dc_decomodel_t *decomodel = (dc_decomodel_t *) value;
|
||||
|
||||
if (size < HEADERSIZE_MIN)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int version = data[3];
|
||||
const deepsix_excursion_layout_t *layout = version == 0 ?
|
||||
&deepsix_excursion_layout_v0 : &deepsix_excursion_layout_v1;
|
||||
|
||||
if (size < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
if (version != 0 && !parser->cached) {
|
||||
dc_status_t rc = deepsix_excursion_parser_samples_foreach_v1(abstract, NULL, NULL);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
}
|
||||
|
||||
unsigned int atmospheric = array_uint16_le(data + layout->atmospheric);
|
||||
unsigned int density = DENSITY;
|
||||
if (layout->salinity != UNDEFINED) {
|
||||
density = 1000 + data[layout->salinity] * 10;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
switch (type) {
|
||||
case DC_FIELD_DIVETIME:
|
||||
*((unsigned int *) value) = array_uint32_le(data + layout->divetime);
|
||||
break;
|
||||
case DC_FIELD_MAXDEPTH:
|
||||
*((double *) value) = pressure_to_depth(array_uint16_le(data + layout->maxdepth), atmospheric, density);
|
||||
break;
|
||||
case DC_FIELD_AVGDEPTH:
|
||||
if (layout->avgdepth == UNDEFINED)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((double *) value) = pressure_to_depth(array_uint16_le(data + layout->avgdepth), atmospheric, density);
|
||||
break;
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
|
||||
gasmix->helium = parser->gasmix[flags].helium / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
break;
|
||||
case DC_FIELD_TEMPERATURE_MINIMUM:
|
||||
*((double *) value) = (signed int) array_uint16_le(data + layout->temperature_min) / 10.0;
|
||||
break;
|
||||
case DC_FIELD_TEMPERATURE_SURFACE:
|
||||
if (layout->temperature_surf == UNDEFINED)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
*((double *) value) = (signed int) array_uint16_le(data + layout->temperature_surf) / 10.0;
|
||||
break;
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
*((double *) value) = atmospheric / 1000.0;
|
||||
break;
|
||||
case DC_FIELD_SALINITY:
|
||||
water->type = (density == 1000) ? DC_WATER_FRESH : DC_WATER_SALT;
|
||||
water->density = density;
|
||||
break;
|
||||
case DC_FIELD_DIVEMODE:
|
||||
switch (data[layout->divemode]) {
|
||||
case 0:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_OC;
|
||||
break;
|
||||
case 1:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_GAUGE;
|
||||
break;
|
||||
case 2:
|
||||
*((dc_divemode_t *) value) = DC_DIVEMODE_FREEDIVE;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_DECOMODEL:
|
||||
decomodel->type = DC_DECOMODEL_BUHLMANN;
|
||||
decomodel->conservatism = 0;
|
||||
if (layout->gf != UNDEFINED) {
|
||||
decomodel->params.gf.low = data[layout->gf + 0];
|
||||
decomodel->params.gf.high = data[layout->gf + 1];
|
||||
} else {
|
||||
decomodel->params.gf.low = 0;
|
||||
decomodel->params.gf.high = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_parser_samples_foreach_v0 (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
const deepsix_excursion_layout_t *layout = &deepsix_excursion_layout_v0;
|
||||
|
||||
if (size < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
int firmware4c = memcmp(data + layout->firmware, "D01-4C", 6) == 0;
|
||||
|
||||
unsigned int maxtype = firmware4c ? TEMPERATURE : CNS;
|
||||
|
||||
unsigned int interval = array_uint32_le(data + layout->samplerate);
|
||||
unsigned int atmospheric = array_uint32_le(data + layout->atmospheric);
|
||||
|
||||
unsigned int time = 0;
|
||||
unsigned int offset = layout->headersize;
|
||||
while (offset + 1 < size) {
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
// Get the sample type.
|
||||
unsigned int type = data[offset];
|
||||
if (type < 1 || type > maxtype) {
|
||||
ERROR (abstract->context, "Unknown sample type (%u).", type);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Get the sample length.
|
||||
unsigned int length = 1;
|
||||
if (type == ALARM || type == CEILING) {
|
||||
length = 8;
|
||||
} else if (type == TEMPERATURE || type == DECO || type == CNS) {
|
||||
length = 6;
|
||||
}
|
||||
|
||||
// Verify the length.
|
||||
if (offset + length > size) {
|
||||
WARNING (abstract->context, "Unexpected end of data.");
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned int misc = data[offset + 1];
|
||||
unsigned int depth = array_uint16_le(data + offset + 2);
|
||||
|
||||
if (type == TEMPERATURE) {
|
||||
time += interval;
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback(DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
sample.depth = pressure_to_depth(depth, atmospheric, DENSITY);
|
||||
if (callback) callback(DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
}
|
||||
|
||||
if (type == ALARM) {
|
||||
unsigned int alarm_time = array_uint16_le(data + offset + 4);
|
||||
unsigned int alarm_value = array_uint16_le(data + offset + 6);
|
||||
} else if (type == TEMPERATURE) {
|
||||
unsigned int temperature = array_uint16_le(data + offset + 4);
|
||||
if (firmware4c) {
|
||||
if (temperature > 1300) {
|
||||
length = 8;
|
||||
} else if (temperature >= 10) {
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
} else {
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
} else if (type == DECO) {
|
||||
unsigned int deco = array_uint16_le(data + offset + 4);
|
||||
} else if (type == CEILING) {
|
||||
unsigned int ceiling_depth = array_uint16_le(data + offset + 4);
|
||||
unsigned int ceiling_time = array_uint16_le(data + offset + 6);
|
||||
} else if (type == CNS) {
|
||||
unsigned int cns = array_uint16_le(data + offset + 4);
|
||||
sample.cns = cns / 100.0;
|
||||
if (callback) callback(DC_SAMPLE_CNS, &sample, userdata);
|
||||
}
|
||||
|
||||
offset += length;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
deepsix_excursion_parser_t *parser = (deepsix_excursion_parser_t *) abstract;
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
const deepsix_excursion_layout_t *layout = &deepsix_excursion_layout_v1;
|
||||
|
||||
if (size < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int headersize = data[2];
|
||||
if (headersize < layout->headersize)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int samplerate = data[layout->samplerate];
|
||||
unsigned int atmospheric = array_uint16_le(data + layout->atmospheric);
|
||||
unsigned int density = 1000 + data[layout->salinity] * 10;
|
||||
|
||||
unsigned int offset = headersize;
|
||||
if (offset + 1 > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned int nconfig = data[offset];
|
||||
if (nconfig > MAX_SAMPLES) {
|
||||
ERROR(abstract->context, "Too many sample descriptors (%u).", nconfig);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
offset += 1;
|
||||
|
||||
if (offset + 3 * nconfig > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
deepsix_excursion_sample_info_t sample_info[MAX_SAMPLES] = {{0}};
|
||||
for (unsigned int i = 0; i < nconfig; i++) {
|
||||
sample_info[i].type = data[offset + 3 * i + 0];
|
||||
sample_info[i].size = data[offset + 3 * i + 1];
|
||||
sample_info[i].divisor = data[offset + 3 * i + 2];
|
||||
|
||||
if (sample_info[i].divisor) {
|
||||
switch (sample_info[i].type) {
|
||||
case SAMPLE_CNS:
|
||||
case SAMPLE_TEMPERATURE:
|
||||
if (sample_info[i].size != 2) {
|
||||
ERROR(abstract->context, "Unexpected sample size (%u).", sample_info[i].size);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case SAMPLE_DECO_NDL:
|
||||
if (sample_info[i].size != 7) {
|
||||
ERROR(abstract->context, "Unexpected sample size (%u).", sample_info[i].size);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARNING (abstract->context, "Unknown sample descriptor (%u %u %u).",
|
||||
sample_info[i].type, sample_info[i].size, sample_info[i].divisor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
offset += 3 * nconfig;
|
||||
|
||||
if (offset + 1 > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned int nevents = data[offset];
|
||||
if (nevents > MAX_EVENTS) {
|
||||
ERROR(abstract->context, "Too many event descriptors (%u).", nevents);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
offset += 1;
|
||||
|
||||
if (offset + 2 * nevents > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
deepsix_excursion_event_info_t event_info[MAX_EVENTS] = {{0}};
|
||||
for (unsigned int i = 0; i < nevents; i++) {
|
||||
event_info[i].type = data[offset + 2 * i];
|
||||
event_info[i].size = data[offset + 2 * i + 1];
|
||||
|
||||
switch (event_info[i].type) {
|
||||
case EVENT_ALARMS:
|
||||
if (event_info[i].size != 1) {
|
||||
ERROR(abstract->context, "Unexpected event size (%u).", event_info[i].size);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case EVENT_CHANGE_GAS:
|
||||
if (event_info[i].size != 3) {
|
||||
ERROR(abstract->context, "Unexpected event size (%u).", event_info[i].size);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case EVENT_SAMPLES_MISSED:
|
||||
if (event_info[i].size != 6) {
|
||||
ERROR(abstract->context, "Unexpected event size (%u).", event_info[i].size);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WARNING (abstract->context, "Unknown event descriptor (%u %u).",
|
||||
event_info[i].type, event_info[i].size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
offset += 2 * nevents;
|
||||
|
||||
unsigned int time = 0;
|
||||
unsigned int nsamples = 0;
|
||||
while (offset + 3 <= size) {
|
||||
dc_sample_value_t sample = {0};
|
||||
nsamples++;
|
||||
|
||||
// Time (seconds).
|
||||
time += samplerate;
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
unsigned int depth = array_uint16_le (data + offset);
|
||||
sample.depth = pressure_to_depth(depth, atmospheric, density);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
offset += 2;
|
||||
|
||||
// event info
|
||||
unsigned int length = data[offset];
|
||||
offset += 1;
|
||||
|
||||
if (offset + length > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
if (length) {
|
||||
if (length < 2) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned int events = array_uint16_le (data + offset);
|
||||
unsigned int event_offset = 2;
|
||||
|
||||
for (unsigned int i = 0; i < nevents; i++) {
|
||||
if ((events & (1 << event_info[i].type)) == 0)
|
||||
continue;
|
||||
|
||||
if (event_offset + event_info[i].size > length) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned int alarms = 0;
|
||||
unsigned int id = 0, o2 = 0, he = 0;
|
||||
unsigned int mix_idx = 0;
|
||||
unsigned int count = 0, timestamp = 0;
|
||||
switch (event_info[i].type) {
|
||||
case EVENT_ALARMS:
|
||||
alarms = data[offset + event_offset];
|
||||
for (unsigned int v = alarms, j = 0; v; v >>= 1, ++j) {
|
||||
if ((v & 1) == 0)
|
||||
continue;
|
||||
|
||||
sample.event.type = SAMPLE_EVENT_NONE;
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = 0;
|
||||
switch (j) {
|
||||
case ALARM_ASCENTRATE:
|
||||
sample.event.type = SAMPLE_EVENT_ASCENT;
|
||||
break;
|
||||
case ALARM_CEILING:
|
||||
sample.event.type = SAMPLE_EVENT_CEILING;
|
||||
break;
|
||||
case ALARM_PO2:
|
||||
sample.event.type = SAMPLE_EVENT_PO2;
|
||||
break;
|
||||
case ALARM_MAXDEPTH:
|
||||
sample.event.type = SAMPLE_EVENT_MAXDEPTH;
|
||||
break;
|
||||
case ALARM_DIVETIME:
|
||||
sample.event.type = SAMPLE_EVENT_DIVETIME;
|
||||
break;
|
||||
case ALARM_CNS:
|
||||
break;
|
||||
default:
|
||||
WARNING (abstract->context, "Unknown event (%u).", j);
|
||||
break;
|
||||
}
|
||||
if (sample.event.type != SAMPLE_EVENT_NONE) {
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EVENT_CHANGE_GAS:
|
||||
id = data[offset + event_offset];
|
||||
o2 = data[offset + event_offset + 1];
|
||||
he = data[offset + event_offset + 2];
|
||||
|
||||
mix_idx = deepsix_excursion_find_gasmix(parser, o2, he, id);
|
||||
if (mix_idx >= parser->ngasmixes) {
|
||||
if (mix_idx >= MAX_GASMIXES) {
|
||||
ERROR (abstract->context, "Maximum number of gas mixes reached.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
parser->gasmix[mix_idx].oxygen = o2;
|
||||
parser->gasmix[mix_idx].helium = he;
|
||||
parser->gasmix[mix_idx].id = id;
|
||||
parser->ngasmixes = mix_idx + 1;
|
||||
}
|
||||
|
||||
sample.gasmix = mix_idx;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
break;
|
||||
case EVENT_SAMPLES_MISSED:
|
||||
count = array_uint16_le(data + offset + event_offset);
|
||||
timestamp = array_uint32_le(data + offset + event_offset + 2);
|
||||
if (timestamp < time) {
|
||||
ERROR (abstract->context, "Timestamp moved backwards (%u %u).", timestamp, time);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
nsamples += count;
|
||||
time = timestamp;
|
||||
break;
|
||||
default:
|
||||
WARNING (abstract->context, "Unknown event (%u %u).",
|
||||
event_info[i].type, event_info[i].size);
|
||||
break;
|
||||
}
|
||||
event_offset += event_info[i].size;
|
||||
}
|
||||
|
||||
// Skip remaining sample bytes (if any).
|
||||
if (event_offset < length) {
|
||||
WARNING (abstract->context, "Remaining %u bytes skipped.", length - event_offset);
|
||||
}
|
||||
offset += length;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < nconfig; ++i) {
|
||||
if (sample_info[i].divisor && (nsamples % sample_info[i].divisor) == 0) {
|
||||
if (offset + sample_info[i].size > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned int value = 0;
|
||||
unsigned int deco_flags = 0, deco_ndl_tts = 0;
|
||||
unsigned int deco_depth = 0, deco_time = 0;
|
||||
switch (sample_info[i].type) {
|
||||
case SAMPLE_TEMPERATURE:
|
||||
value = array_uint16_le(data + offset);
|
||||
sample.temperature = value / 10.0;
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
break;
|
||||
case SAMPLE_CNS:
|
||||
value = array_uint16_le(data + offset);
|
||||
sample.cns = value / 10000.0;
|
||||
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata);
|
||||
break;
|
||||
case SAMPLE_DECO_NDL:
|
||||
deco_flags = data[offset];
|
||||
deco_ndl_tts = array_uint16_le(data + offset + 1);
|
||||
deco_depth = array_uint16_le(data + offset + 3);
|
||||
deco_time = array_uint16_le(data + offset + 5);
|
||||
if (deco_flags & DECOSTOP) {
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = pressure_to_depth(deco_depth, atmospheric, density);
|
||||
sample.deco.time = deco_time;
|
||||
} else if (deco_flags & SAFETYSTOP) {
|
||||
sample.deco.type = DC_DECO_SAFETYSTOP;
|
||||
sample.deco.depth = pressure_to_depth(deco_depth, atmospheric, density);
|
||||
sample.deco.time = deco_time;
|
||||
} else {
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.depth = 0;
|
||||
sample.deco.time = deco_ndl_tts;
|
||||
}
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
offset += sample_info[i].size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parser->cached = 1;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
const unsigned char *data = abstract->data;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
if (size < HEADERSIZE_MIN)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
unsigned int version = data[3];
|
||||
|
||||
if (version == 0) {
|
||||
return deepsix_excursion_parser_samples_foreach_v0(abstract, callback, userdata);
|
||||
} else {
|
||||
return deepsix_excursion_parser_samples_foreach_v1(abstract, callback, userdata);
|
||||
}
|
||||
}
|
||||
277
src/descriptor.c
277
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,37 +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_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_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_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);
|
||||
|
||||
@ -130,11 +125,13 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Suunto", "DX", DC_FAMILY_SUUNTO_D9, 0x1C, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Suunto", "Vyper Novo", DC_FAMILY_SUUNTO_D9, 0x1D, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Suunto", "Zoop Novo", DC_FAMILY_SUUNTO_D9, 0x1E, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Suunto", "Zoop Novo", DC_FAMILY_SUUNTO_D9, 0x1F, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Suunto", "D4f", DC_FAMILY_SUUNTO_D9, 0x20, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Suunto EON Steel */
|
||||
{"Suunto", "EON Steel", DC_FAMILY_SUUNTO_EONSTEEL, 0, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_suunto},
|
||||
{"Suunto", "EON Core", DC_FAMILY_SUUNTO_EONSTEEL, 1, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_suunto},
|
||||
{"Suunto", "D5", DC_FAMILY_SUUNTO_EONSTEEL, 2, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_suunto},
|
||||
{"Suunto", "EON Steel", DC_FAMILY_SUUNTO_EONSTEEL, 0, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_suunto},
|
||||
{"Suunto", "EON Core", DC_FAMILY_SUUNTO_EONSTEEL, 1, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_suunto},
|
||||
{"Suunto", "D5", DC_FAMILY_SUUNTO_EONSTEEL, 2, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_suunto},
|
||||
{"Suunto", "EON Steel Black", DC_FAMILY_SUUNTO_EONSTEEL, 3, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_suunto},
|
||||
/* Uwatec Aladin */
|
||||
{"Uwatec", "Aladin Air Twin", DC_FAMILY_UWATEC_ALADIN, 0x1C, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Uwatec", "Aladin Sport Plus", DC_FAMILY_UWATEC_ALADIN, 0x3E, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -172,9 +169,14 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Scubapro", "Chromis", DC_FAMILY_UWATEC_SMART, 0x24, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Scubapro", "Aladin A1", DC_FAMILY_UWATEC_SMART, 0x25, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "Mantis 2", DC_FAMILY_UWATEC_SMART, 0x26, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Scubapro", "Aladin A2", DC_FAMILY_UWATEC_SMART, 0x28, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G2 TEK", DC_FAMILY_UWATEC_SMART, 0x31, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G2", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G2 Console", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G3", DC_FAMILY_UWATEC_SMART, 0x34, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G2 HUD", DC_FAMILY_UWATEC_SMART, 0x42, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "Luna 2.0 AI", DC_FAMILY_UWATEC_SMART, 0x50, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "Luna 2.0", DC_FAMILY_UWATEC_SMART, 0x51, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
/* Reefnet */
|
||||
{"Reefnet", "Sensus", DC_FAMILY_REEFNET_SENSUS, 1, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Reefnet", "Sensus Pro", DC_FAMILY_REEFNET_SENSUSPRO, 2, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -253,10 +255,11 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Sherwood", "Vision", DC_FAMILY_OCEANIC_ATOM2, 0x4556, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Oceanic", "VTX", DC_FAMILY_OCEANIC_ATOM2, 0x4557, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Aqualung", "i300", DC_FAMILY_OCEANIC_ATOM2, 0x4559, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Aqualung", "i750TC", DC_FAMILY_OCEANIC_ATOM2, 0x455A, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLUETOOTH, NULL},
|
||||
{"Aqualung", "i750TC", DC_FAMILY_OCEANIC_ATOM2, 0x455A, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i450T", DC_FAMILY_OCEANIC_ATOM2, 0x4641, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Aqualung", "i550", DC_FAMILY_OCEANIC_ATOM2, 0x4642, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Aqualung", "i200", DC_FAMILY_OCEANIC_ATOM2, 0x4646, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Sherwood", "Sage", DC_FAMILY_OCEANIC_ATOM2, 0x4647, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i300C", DC_FAMILY_OCEANIC_ATOM2, 0x4648, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i200C", DC_FAMILY_OCEANIC_ATOM2, 0x4649, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i100", DC_FAMILY_OCEANIC_ATOM2, 0x464E, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -266,7 +269,15 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Oceanic", "Veo 4.0", DC_FAMILY_OCEANIC_ATOM2, 0x4654, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Sherwood", "Wisdom 4", DC_FAMILY_OCEANIC_ATOM2, 0x4655, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Oceanic", "Pro Plus 4", DC_FAMILY_OCEANIC_ATOM2, 0x4656, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Sherwood", "Amphos 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4657, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Sherwood", "Amphos Air 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4658, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Sherwood", "Beacon", DC_FAMILY_OCEANIC_ATOM2, 0x4742, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i470TC", DC_FAMILY_OCEANIC_ATOM2, 0x4743, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i200Cv2", DC_FAMILY_OCEANIC_ATOM2, 0x4749, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Oceanic", "Geo Air", DC_FAMILY_OCEANIC_ATOM2, 0x474B, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
/* Pelagic I330R */
|
||||
{"Apeks", "DSX", DC_FAMILY_PELAGIC_I330R, 0x4741, DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i330R", DC_FAMILY_PELAGIC_I330R, 0x4744, DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
/* Mares Nemo */
|
||||
{"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -291,12 +302,14 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Mares", "Icon HD", DC_FAMILY_MARES_ICONHD , 0x14, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Mares", "Icon HD Net Ready", DC_FAMILY_MARES_ICONHD , 0x15, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Mares", "Puck Pro", DC_FAMILY_MARES_ICONHD , 0x18, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
||||
{"Mares", "Puck Pro +", DC_FAMILY_MARES_ICONHD , 0x18, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
||||
{"Mares", "Nemo Wide 2", DC_FAMILY_MARES_ICONHD , 0x19, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Mares", "Genius", DC_FAMILY_MARES_ICONHD , 0x1C, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
||||
{"Mares", "Puck 2", DC_FAMILY_MARES_ICONHD , 0x1F, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Mares", "Quad Air", DC_FAMILY_MARES_ICONHD , 0x23, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
||||
{"Mares", "Smart Air", DC_FAMILY_MARES_ICONHD , 0x24, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
||||
{"Mares", "Quad", DC_FAMILY_MARES_ICONHD , 0x29, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
||||
{"Mares", "Horizon", DC_FAMILY_MARES_ICONHD , 0x2C, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Heinrichs Weikamp */
|
||||
{"Heinrichs Weikamp", "OSTC", DC_FAMILY_HW_OSTC, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Heinrichs Weikamp", "OSTC Mk2", DC_FAMILY_HW_OSTC, 1, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -324,8 +337,11 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Cressi", "Newton", DC_FAMILY_CRESSI_LEONARDO, 5, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Cressi", "Drake", DC_FAMILY_CRESSI_LEONARDO, 6, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Cressi Goa */
|
||||
{"Cressi", "Cartesio", DC_FAMILY_CRESSI_GOA, 1, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, NULL},
|
||||
{"Cressi", "Goa", DC_FAMILY_CRESSI_GOA, 2, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, NULL},
|
||||
{"Cressi", "Cartesio", DC_FAMILY_CRESSI_GOA, 1, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Cressi", "Goa", DC_FAMILY_CRESSI_GOA, 2, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Cressi", "Donatello", DC_FAMILY_CRESSI_GOA, 4, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Cressi", "Michelangelo", DC_FAMILY_CRESSI_GOA, 5, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Cressi", "Neon", DC_FAMILY_CRESSI_GOA, 9, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Zeagle N2iTiON3 */
|
||||
{"Zeagle", "N2iTiON3", DC_FAMILY_ZEAGLE_N2ITION3, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Apeks", "Quantum X", DC_FAMILY_ZEAGLE_N2ITION3, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -345,6 +361,9 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Shearwater", "Nerd 2", DC_FAMILY_SHEARWATER_PETREL, 7, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Teric", DC_FAMILY_SHEARWATER_PETREL, 8, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Peregrine", DC_FAMILY_SHEARWATER_PETREL, 9, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Petrel 3", DC_FAMILY_SHEARWATER_PETREL, 10, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Perdix 2", DC_FAMILY_SHEARWATER_PETREL, 11, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Tern", DC_FAMILY_SHEARWATER_PETREL, 12, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
/* Dive Rite NiTek Q */
|
||||
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Citizen Hyper Aqualand */
|
||||
@ -386,6 +405,37 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Ratio", "iDive Color Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x54, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iDive Color Tech+",DC_FAMILY_DIVESYSTEM_IDIVE, 0x55, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iDive Color Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x56, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iX3M 2021 GPS Fancy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x60, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2021 GPS Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x61, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2021 GPS Pro ", DC_FAMILY_DIVESYSTEM_IDIVE, 0x62, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2021 GPS Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x63, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2021 GPS Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x64, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2021 GPS Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x65, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2021 Pro Fancy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x70, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iX3M 2021 Pro Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x71, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iX3M 2021 Pro Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x72, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iX3M 2021 Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x73, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iX3M 2021 Pro Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x74, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iX3M 2021 Pro Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x75, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iDive 2 Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x80, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Fancy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x81, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x82, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x83, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x84, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Tech", DC_FAMILY_DIVESYSTEM_IDIVE, 0x85, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x86, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Gauge", DC_FAMILY_DIVESYSTEM_IDIVE, 0x90, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x91, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x92, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x93, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Tech", DC_FAMILY_DIVESYSTEM_IDIVE, 0x94, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x95, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "ATOM", DC_FAMILY_DIVESYSTEM_IDIVE, 0x96, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Gauge", DC_FAMILY_DIVESYSTEM_IDIVE, 0x100, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x101, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x102, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x103, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x104, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Seac", "Jack", DC_FAMILY_DIVESYSTEM_IDIVE, 0x1000, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Seac", "Guru", DC_FAMILY_DIVESYSTEM_IDIVE, 0x1002, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Cochran Commander */
|
||||
@ -404,14 +454,32 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Liquivision", "Xeo", DC_FAMILY_LIQUIVISION_LYNX, 1, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Liquivision", "Lynx", DC_FAMILY_LIQUIVISION_LYNX, 2, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Liquivision", "Kaon", DC_FAMILY_LIQUIVISION_LYNX, 3, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Sporasub */
|
||||
{"Sporasub", "SP2", DC_FAMILY_SPORASUB_SP2, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Deep Six Excursion */
|
||||
{"Deep Six", "Excursion", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||
{"Crest", "CR-4", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||
{"Genesis", "Centauri", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||
{"Scorpena", "Alpha", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||
/* Seac Screen */
|
||||
{"Seac", "Screen", DC_FAMILY_SEAC_SCREEN, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Seac", "Action", DC_FAMILY_SEAC_SCREEN, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Deepblu Cosmiq */
|
||||
{"Deepblu", "Cosmiq+", DC_FAMILY_DEEPBLU_COSMIQ, 0, DC_TRANSPORT_BLE, dc_filter_deepblu},
|
||||
/* Oceans S1 */
|
||||
{"Oceans", "S1", DC_FAMILY_OCEANS_S1, 0, DC_TRANSPORT_BLE, dc_filter_oceans},
|
||||
/* Divesoft Freedom */
|
||||
{"Divesoft", "Freedom", DC_FAMILY_DIVESOFT_FREEDOM, 19, DC_TRANSPORT_BLE, dc_filter_divesoft},
|
||||
{"Divesoft", "Liberty", DC_FAMILY_DIVESOFT_FREEDOM, 10, DC_TRANSPORT_BLE, dc_filter_divesoft},
|
||||
|
||||
// Not merged upstream yet
|
||||
/* Garmin */
|
||||
{"Garmin", "Descent Mk1", DC_FAMILY_GARMIN, 2859, DC_TRANSPORT_USBSTORAGE, dc_filter_garmin},
|
||||
/* Deepblu */
|
||||
{"Deepblu", "Cosmiq+", DC_FAMILY_DEEPBLU, 0, DC_TRANSPORT_BLE, dc_filter_deepblu},
|
||||
/* Oceans S1 */
|
||||
{ "Oceans", "S1", DC_FAMILY_OCEANS_S1, 0, DC_TRANSPORT_BLE, dc_filter_oceans },
|
||||
/* Garmin -- model numbers as defined in FIT format; USB product id is (0x4000 | model) */
|
||||
/* for the Mk1 we are using the model of the global model */
|
||||
/* for the Mk2/Mk3 we are using the model of the Mk2 global model */
|
||||
/* see garmin_parser.c for a more comprehensive list of models */
|
||||
{"Garmin", "Descent Mk1", DC_FAMILY_GARMIN, 2859, DC_TRANSPORT_USBSTORAGE, NULL},
|
||||
{"Garmin", "Descent Mk2(i)/Mk3(i)", DC_FAMILY_GARMIN, 3258, DC_TRANSPORT_USBSTORAGE, NULL},
|
||||
{"FIT", "File import", DC_FAMILY_GARMIN, 0, DC_TRANSPORT_USBSTORAGE, NULL },
|
||||
};
|
||||
|
||||
static int
|
||||
@ -450,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)
|
||||
{
|
||||
@ -484,20 +561,19 @@ dc_match_oceanic (const void *key, const void *value)
|
||||
0
|
||||
};
|
||||
|
||||
return dc_match_number_with_prefix (key, &prefix);
|
||||
const char *p = prefix;
|
||||
|
||||
return dc_match_number_with_prefix (key, &p);
|
||||
}
|
||||
|
||||
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 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -512,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",
|
||||
@ -523,8 +600,8 @@ 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[] = {
|
||||
{0x2e6c, 0x3201}, // G2
|
||||
static const dc_usbhid_desc_t usbhid[] = {
|
||||
{0x2e6c, 0x3201}, // G2, G2 TEK
|
||||
{0x2e6c, 0x3211}, // G2 Console
|
||||
{0x2e6c, 0x4201}, // G2 HUD
|
||||
{0xc251, 0x2006}, // Aladin Square
|
||||
@ -534,12 +611,17 @@ static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, voi
|
||||
"Aladin",
|
||||
"HUD",
|
||||
"A1",
|
||||
"A2",
|
||||
"G2 TEK",
|
||||
"Galileo 3",
|
||||
"Luna 2.0 AI",
|
||||
"Luna 2.0",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_IRDA) {
|
||||
return DC_FILTER_INTERNAL (userdata, irda, 0, dc_match_name);
|
||||
} else if (transport == DC_TRANSPORT_USBHID) {
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_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);
|
||||
}
|
||||
@ -547,21 +629,24 @@ 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
|
||||
{0x1493, 0x0036}, // EON Steel Black
|
||||
};
|
||||
static const char * const bluetooth[] = {
|
||||
"EON Steel",
|
||||
"EON Core",
|
||||
"Suunto D5",
|
||||
"EON Steel Black",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_USBHID) {
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_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);
|
||||
}
|
||||
@ -569,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",
|
||||
@ -585,16 +671,20 @@ 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",
|
||||
"Petrel",
|
||||
"Petrel 3",
|
||||
"NERD",
|
||||
"NERD 2",
|
||||
"Perdix",
|
||||
"Perdix 2",
|
||||
"Teric",
|
||||
"Peregrine",
|
||||
"Tern"
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
|
||||
@ -606,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",
|
||||
@ -621,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",
|
||||
@ -635,23 +727,29 @@ 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) {
|
||||
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_number_with_prefix);
|
||||
}
|
||||
|
||||
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
|
||||
0x455A, // Aqualung i750TC
|
||||
0x4647, // Sherwood Sage
|
||||
0x4648, // Aqualung i300C
|
||||
0x4649, // Aqualung i200C
|
||||
0x4651, // Aqualung i770R
|
||||
@ -660,7 +758,12 @@ 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
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
@ -670,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",
|
||||
@ -685,38 +789,39 @@ 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;
|
||||
}
|
||||
|
||||
// Not merged upstream yet
|
||||
static int dc_filter_garmin (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 dc_usb_desc_t usbhid[] = {
|
||||
{0x091e, 0x2b2b}, // Garmin Descent Mk1
|
||||
static const char * const bluetooth[] = {
|
||||
"EXCURSION",
|
||||
"Crest-CR4",
|
||||
"CENTAURI",
|
||||
"ALPHA",
|
||||
};
|
||||
|
||||
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_name);
|
||||
}
|
||||
|
||||
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",
|
||||
@ -729,14 +834,30 @@ 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 ble[] = {
|
||||
static const char * const bluetooth[] = {
|
||||
"S1",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
return DC_FILTER_INTERNAL(userdata, ble, 0, dc_match_prefix);
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_divesoft (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"Freedom",
|
||||
"Liberty",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -834,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)
|
||||
if (descriptor == NULL || descriptor->filter == NULL || userdata == NULL)
|
||||
return 1;
|
||||
|
||||
return descriptor->filter (transport, userdata, params);
|
||||
return descriptor->filter (descriptor, transport, userdata);
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ int
|
||||
device_is_cancelled (dc_device_t *device);
|
||||
|
||||
dc_status_t
|
||||
device_dump_read (dc_device_t *device, unsigned char data[], unsigned int size, unsigned int blocksize);
|
||||
device_dump_read (dc_device_t *device, unsigned int address, unsigned char data[], unsigned int size, unsigned int blocksize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
45
src/device.c
45
src/device.c
@ -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"
|
||||
@ -59,11 +60,15 @@
|
||||
#include "tecdiving_divecomputereu.h"
|
||||
#include "mclean_extreme.h"
|
||||
#include "liquivision_lynx.h"
|
||||
#include "sporasub_sp2.h"
|
||||
#include "deepsix_excursion.h"
|
||||
#include "seac_screen.h"
|
||||
#include "deepblu_cosmiq.h"
|
||||
#include "oceans_s1.h"
|
||||
#include "divesoft_freedom.h"
|
||||
|
||||
// Not merged upstream yet
|
||||
#include "garmin.h"
|
||||
#include "deepblu.h"
|
||||
#include "oceans_s1.h"
|
||||
|
||||
#include "device-private.h"
|
||||
#include "context-private.h"
|
||||
@ -161,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;
|
||||
@ -224,18 +232,30 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
|
||||
case DC_FAMILY_LIQUIVISION_LYNX:
|
||||
rc = liquivision_lynx_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_SPORASUB_SP2:
|
||||
rc = sporasub_sp2_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_DEEPSIX_EXCURSION:
|
||||
rc = deepsix_excursion_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_SEAC_SCREEN:
|
||||
rc = seac_screen_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_DEEPBLU_COSMIQ:
|
||||
rc = deepblu_cosmiq_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_OCEANS_S1:
|
||||
rc = oceans_s1_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_DIVESOFT_FREEDOM:
|
||||
rc = divesoft_freedom_device_open (&device, context, iostream);
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Not merged upstream yet
|
||||
case DC_FAMILY_GARMIN:
|
||||
rc = garmin_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_DEEPBLU:
|
||||
rc = deepblu_device_open (&device, context, iostream);
|
||||
break;
|
||||
case DC_FAMILY_OCEANS_S1:
|
||||
rc = oceans_s1_device_open(&device, context, iostream);
|
||||
rc = garmin_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -350,7 +370,7 @@ dc_device_dump (dc_device_t *device, dc_buffer_t *buffer)
|
||||
|
||||
|
||||
dc_status_t
|
||||
device_dump_read (dc_device_t *device, unsigned char data[], unsigned int size, unsigned int blocksize)
|
||||
device_dump_read (dc_device_t *device, unsigned int address, unsigned char data[], unsigned int size, unsigned int blocksize)
|
||||
{
|
||||
if (device == NULL)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
@ -371,7 +391,7 @@ device_dump_read (dc_device_t *device, unsigned char data[], unsigned int size,
|
||||
len = blocksize;
|
||||
|
||||
// Read the packet.
|
||||
dc_status_t rc = device->vtable->read (device, nbytes, data + nbytes, len);
|
||||
dc_status_t rc = device->vtable->read (device, address + nbytes, data + nbytes, len);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
@ -408,6 +428,9 @@ dc_device_timesync (dc_device_t *device, const dc_datetime_t *datetime)
|
||||
if (device->vtable->timesync == NULL)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
|
||||
if (datetime == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
return device->vtable->timesync (device, datetime);
|
||||
}
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
diverite_nitekq_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
diverite_nitekq_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
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,9 @@ 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 */
|
||||
diverite_nitekq_parser_get_datetime, /* datetime */
|
||||
diverite_nitekq_parser_get_field, /* fields */
|
||||
diverite_nitekq_parser_samples_foreach, /* samples_foreach */
|
||||
@ -66,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;
|
||||
|
||||
@ -74,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;
|
||||
@ -98,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)
|
||||
{
|
||||
@ -158,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;
|
||||
@ -261,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;
|
||||
}
|
||||
|
||||
@ -279,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) {
|
||||
@ -290,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;
|
||||
}
|
||||
43
src/divesoft_freedom.h
Normal file
43
src/divesoft_freedom.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2023 Jan Matoušek, Jef Driesen
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef DIVESOFT_FREEDOM_H
|
||||
#define DIVESOFT_FREEDOM_H
|
||||
|
||||
#include <libdivecomputer/context.h>
|
||||
#include <libdivecomputer/iostream.h>
|
||||
#include <libdivecomputer/device.h>
|
||||
#include <libdivecomputer/parser.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
dc_status_t
|
||||
divesoft_freedom_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
divesoft_freedom_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* DIVESOFT_FREEDOM_H */
|
||||
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,8 +29,7 @@
|
||||
#include "platform.h"
|
||||
#include "checksum.h"
|
||||
#include "array.h"
|
||||
|
||||
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
|
||||
#include "packet.h"
|
||||
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &divesystem_idive_device_vtable)
|
||||
|
||||
@ -104,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),
|
||||
@ -114,7 +114,7 @@ static const dc_device_vtable_t divesystem_idive_device_vtable = {
|
||||
NULL, /* dump */
|
||||
divesystem_idive_device_foreach, /* foreach */
|
||||
divesystem_idive_device_timesync, /* timesync */
|
||||
NULL /* close */
|
||||
divesystem_idive_device_close /* close */
|
||||
};
|
||||
|
||||
static const divesystem_idive_commands_t idive = {
|
||||
@ -154,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;
|
||||
@ -166,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.
|
||||
@ -192,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)
|
||||
@ -233,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;
|
||||
|
||||
@ -294,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;
|
||||
@ -610,11 +637,6 @@ divesystem_idive_device_timesync (dc_device_t *abstract, const dc_datetime_t *da
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
if (datetime == NULL) {
|
||||
ERROR (abstract->context, "Invalid parameter specified.");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
// Get the UTC timestamp.
|
||||
dc_ticks_t timestamp = dc_datetime_mktime(datetime);
|
||||
if (timestamp == -1) {
|
||||
@ -903,6 +925,9 @@ divesystem_idive_device_fwupdate (dc_device_t *abstract, const char *filename)
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Wait before sending the firmware data.
|
||||
dc_iostream_sleep (device->iostream, 100);
|
||||
|
||||
// Upload the firmware.
|
||||
unsigned int offset = 0;
|
||||
while (offset + 2 <= size) {
|
||||
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
divesystem_idive_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_parser_create (dc_parser_t **parser, dc_context_t *context, 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
|
||||
}
|
||||
|
||||
@ -26,11 +26,10 @@
|
||||
#include "parser-private.h"
|
||||
#include "array.h"
|
||||
|
||||
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
|
||||
|
||||
#define ISINSTANCE(parser) dc_device_isinstance((parser), &divesystem_idive_parser_vtable)
|
||||
|
||||
#define ISIX3M(model) ((model) >= 0x21)
|
||||
#define ISIX3M2(model) ((model) >= 0x60 && (model) < 0x1000)
|
||||
|
||||
#define SZ_HEADER_IDIVE 0x32
|
||||
#define SZ_SAMPLE_IDIVE 0x2A
|
||||
@ -50,6 +49,18 @@
|
||||
#define FREEDIVE 4
|
||||
#define INVALID 0xFFFFFFFF
|
||||
|
||||
#define BUHLMANN 0
|
||||
#define VPM 1
|
||||
#define DUAL 2
|
||||
|
||||
#define IX3M2_BUHLMANN 0
|
||||
#define IX3M2_ZHL16B 1
|
||||
#define IX3M2_ZHL16C 2
|
||||
#define IX3M2_VPM 3
|
||||
|
||||
#define REC_SAMPLE 0
|
||||
#define REC_INFO 1
|
||||
|
||||
typedef struct divesystem_idive_parser_t divesystem_idive_parser_t;
|
||||
|
||||
typedef struct divesystem_idive_gasmix_t {
|
||||
@ -76,9 +87,11 @@ struct divesystem_idive_parser_t {
|
||||
unsigned int ntanks;
|
||||
divesystem_idive_gasmix_t gasmix[NGASMIXES];
|
||||
divesystem_idive_tank_t tank[NTANKS];
|
||||
unsigned int algorithm;
|
||||
unsigned int gf_low;
|
||||
unsigned int gf_high;
|
||||
};
|
||||
|
||||
static dc_status_t divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t divesystem_idive_parser_get_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);
|
||||
@ -86,7 +99,9 @@ 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 */
|
||||
divesystem_idive_parser_get_datetime, /* datetime */
|
||||
divesystem_idive_parser_get_field, /* fields */
|
||||
divesystem_idive_parser_samples_foreach, /* samples_foreach */
|
||||
@ -95,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;
|
||||
|
||||
@ -103,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;
|
||||
@ -131,6 +146,10 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, unsign
|
||||
parser->tank[i].beginpressure = 0;
|
||||
parser->tank[i].endpressure = 0;
|
||||
}
|
||||
parser->algorithm = INVALID;
|
||||
parser->gf_low = INVALID;
|
||||
parser->gf_high = INVALID;
|
||||
|
||||
|
||||
*out = (dc_parser_t*) parser;
|
||||
|
||||
@ -138,32 +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;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -282,6 +275,7 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
dc_tank_t *tank = (dc_tank_t *) value;
|
||||
dc_salinity_t *water = (dc_salinity_t *) value;
|
||||
dc_decomodel_t *decomodel = (dc_decomodel_t *) value;
|
||||
|
||||
if (value) {
|
||||
switch (type) {
|
||||
@ -295,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;
|
||||
@ -309,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)) {
|
||||
@ -322,7 +318,7 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
water->density = 0.0;
|
||||
break;
|
||||
case DC_FIELD_DIVEMODE:
|
||||
if (parser->divemode == 0xFFFFFFFF)
|
||||
if (parser->divemode == INVALID)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
switch (parser->divemode) {
|
||||
case OC:
|
||||
@ -345,6 +341,46 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_DECOMODEL:
|
||||
if (parser->algorithm == INVALID)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
if (ISIX3M2(parser->model)) {
|
||||
switch (parser->algorithm) {
|
||||
case IX3M2_BUHLMANN:
|
||||
case IX3M2_ZHL16B:
|
||||
case IX3M2_ZHL16C:
|
||||
decomodel->type = DC_DECOMODEL_BUHLMANN;
|
||||
decomodel->conservatism = 0;
|
||||
decomodel->params.gf.low = parser->gf_low;
|
||||
decomodel->params.gf.high = parser->gf_high;
|
||||
break;
|
||||
case IX3M2_VPM:
|
||||
decomodel->type = DC_DECOMODEL_VPM;
|
||||
decomodel->conservatism = 0;
|
||||
break;
|
||||
default:
|
||||
ERROR (abstract->context, "Unknown deco algorithm %02x.", parser->algorithm);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
} else {
|
||||
switch (parser->algorithm) {
|
||||
case BUHLMANN:
|
||||
case DUAL:
|
||||
decomodel->type = DC_DECOMODEL_BUHLMANN;
|
||||
decomodel->conservatism = 0;
|
||||
decomodel->params.gf.low = parser->gf_low;
|
||||
decomodel->params.gf.high = parser->gf_high;
|
||||
break;
|
||||
case VPM:
|
||||
decomodel->type = DC_DECOMODEL_VPM;
|
||||
decomodel->conservatism = 0;
|
||||
break;
|
||||
default:
|
||||
ERROR (abstract->context, "Unknown deco algorithm %02x.", parser->algorithm);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
@ -367,12 +403,17 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
unsigned int ntanks = 0;
|
||||
divesystem_idive_gasmix_t gasmix[NGASMIXES] = {0};
|
||||
divesystem_idive_tank_t tank[NTANKS] = {0};
|
||||
unsigned int o2_previous = 0xFFFFFFFF;
|
||||
unsigned int he_previous = 0xFFFFFFFF;
|
||||
unsigned int o2_previous = INVALID;
|
||||
unsigned int he_previous = INVALID;
|
||||
unsigned int mode_previous = INVALID;
|
||||
unsigned int divemode = INVALID;
|
||||
unsigned int tank_previous = INVALID;
|
||||
unsigned int tank_idx = INVALID;
|
||||
unsigned int algorithm = INVALID;
|
||||
unsigned int algorithm_previous = INVALID;
|
||||
unsigned int gf_low = INVALID;
|
||||
unsigned int gf_high = INVALID;
|
||||
unsigned int have_bearing = 0;
|
||||
|
||||
unsigned int firmware = 0;
|
||||
unsigned int apos4 = 0;
|
||||
@ -401,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];
|
||||
@ -435,11 +486,27 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
divemode = mode;
|
||||
}
|
||||
|
||||
// Deco model
|
||||
unsigned int s_algorithm = data[offset + 14];
|
||||
unsigned int s_gf_high = data[offset + 15];
|
||||
unsigned int s_gf_low = data[offset + 16];
|
||||
if (s_algorithm != algorithm_previous) {
|
||||
if (algorithm_previous != INVALID) {
|
||||
WARNING (abstract->context, "Deco algorithm changed from %02x to %02x.", algorithm_previous, s_algorithm);
|
||||
}
|
||||
algorithm_previous = s_algorithm;
|
||||
}
|
||||
if (algorithm == INVALID) {
|
||||
algorithm = s_algorithm;
|
||||
gf_low = s_gf_low;
|
||||
gf_high = s_gf_high;
|
||||
}
|
||||
|
||||
// Setpoint
|
||||
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.
|
||||
@ -466,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;
|
||||
}
|
||||
@ -484,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) {
|
||||
@ -503,6 +572,11 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
unsigned int flags = data[offset + 47] & 0xF0;
|
||||
unsigned int pressure = data[offset + 49];
|
||||
|
||||
if (flags & 0x20) {
|
||||
// 300 bar transmitter.
|
||||
pressure *= 2;
|
||||
}
|
||||
|
||||
if (flags & 0x80) {
|
||||
// No active transmitter available
|
||||
} else if (flags & 0x40) {
|
||||
@ -511,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) {
|
||||
@ -541,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;
|
||||
@ -562,6 +646,9 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
parser->maxdepth = maxdepth;
|
||||
parser->divetime = time;
|
||||
parser->divemode = divemode;
|
||||
parser->algorithm = algorithm;
|
||||
parser->gf_low = gf_low;
|
||||
parser->gf_high = gf_high;
|
||||
parser->cached = 1;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
* The field cache 'string' interface has some simple rules:
|
||||
* the "descriptor" part is assumed to be a static allocation,
|
||||
* while the "value" is something that this interface will
|
||||
* alway sallocate with 'strdup()', so you can generate it
|
||||
* always allocate with 'strdup()', so you can generate it
|
||||
* dynamically on the stack or whatever without having to
|
||||
* worry about it.
|
||||
*/
|
||||
@ -71,6 +71,9 @@ dc_status_t dc_field_get_string(dc_field_cache_t *cache, unsigned idx, dc_field_
|
||||
dc_status_t
|
||||
dc_field_get(dc_field_cache_t *cache, dc_field_type_t type, unsigned int flags, void* value)
|
||||
{
|
||||
if (!value)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (!(cache->initialized & (1 << type)))
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
|
||||
@ -82,16 +85,31 @@ 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;
|
||||
return DC_FIELD_INDEX(*cache, value, GASMIX, flags);
|
||||
case DC_FIELD_SALINITY:
|
||||
return DC_FIELD_VALUE(*cache, value, SALINITY);
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
return DC_FIELD_VALUE(*cache, value, ATMOSPHERIC);
|
||||
case DC_FIELD_DIVEMODE:
|
||||
return DC_FIELD_VALUE(*cache, value, DIVEMODE);
|
||||
case DC_FIELD_TANK:
|
||||
if (flags >= MAXGASES)
|
||||
break;
|
||||
|
||||
dc_tank_t *tank = (dc_tank_t *) value;
|
||||
|
||||
tank->volume = cache->tanksize[flags];
|
||||
tank->gasmix = flags;
|
||||
tank->workpressure = cache->tankworkingpressure[flags];
|
||||
tank->type = cache->tankinfo[flags];
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
case DC_FIELD_STRING:
|
||||
return dc_field_get_string(cache, flags, (dc_field_string_t *)value);
|
||||
default:
|
||||
|
||||
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