Compare commits
246 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72a88b18d9 | ||
|
|
eb4b082b1b | ||
|
|
8fe598e1b0 | ||
|
|
1663997111 | ||
|
|
f20d9cb972 | ||
|
|
4516842a5a | ||
|
|
9a603fa8cf | ||
|
|
89a28427d6 | ||
|
|
4914f6bff3 | ||
|
|
dcf842cd9d | ||
|
|
8745a3b95a | ||
|
|
a86cb92ed8 | ||
|
|
b8c3a09c6f | ||
|
|
6903a66cc5 | ||
|
|
9070da3570 | ||
|
|
8e349d4046 | ||
|
|
47f6949db1 | ||
|
|
9070b7d035 | ||
|
|
4cc0bc25ae | ||
|
|
f49af5208c | ||
|
|
b9d7684552 | ||
|
|
ae292253ba | ||
|
|
a91a7dbc38 | ||
|
|
121c7c12fb | ||
|
|
f42449b101 | ||
|
|
aa2dbac509 | ||
|
|
60a9b889de | ||
|
|
4139509238 | ||
|
|
1ba7e5cad0 | ||
|
|
04fe252625 | ||
|
|
9090f713b4 | ||
|
|
00b0169578 | ||
|
|
e0cf41a14e | ||
|
|
f5f855d428 | ||
|
|
811ae7de82 | ||
|
|
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 | ||
|
|
8bfbb94087 | ||
|
|
9cde393e5f | ||
|
|
9bc742d3ac | ||
|
|
a4cd21b811 | ||
|
|
f77e9c03fc | ||
|
|
f818a5a92a | ||
|
|
ceaaba3e77 | ||
|
|
0afd62d7af | ||
|
|
3a68af418e | ||
|
|
ff0328537e | ||
|
|
3d82d6796f | ||
|
|
25bd1f9853 | ||
|
|
c16530b8ab | ||
|
|
d4402aa296 | ||
|
|
13705f2b2d | ||
|
|
ee147afceb | ||
|
|
9b7aa813e0 | ||
|
|
63f5a4d652 | ||
|
|
679db0bae6 | ||
|
|
0a4f37770f | ||
|
|
4e24b3a277 | ||
|
|
becb8bd36e | ||
|
|
4b383a778e | ||
|
|
b1ff2c6a8e | ||
|
|
bca8f9e2d2 | ||
|
|
a34e909a84 | ||
|
|
070de23b83 | ||
|
|
db9371cf9f | ||
|
|
49aa12b172 | ||
|
|
2f1b99f2f9 | ||
|
|
6c3bbb2cc7 | ||
|
|
1c8cd096b5 | ||
|
|
40c95ca02a | ||
|
|
72ddd6a439 | ||
|
|
d4472b758f | ||
|
|
b0e77fd05f | ||
|
|
cee9a2e926 | ||
|
|
9c38ae3e01 | ||
|
|
629d567381 | ||
|
|
bec4a747ff | ||
|
|
43f48af418 | ||
|
|
e45c62b028 | ||
|
|
767a2fad91 | ||
|
|
083b1eb8de | ||
|
|
118f6d79ba | ||
|
|
cf221de9b7 | ||
|
|
86fd58c8c6 | ||
|
|
1930b9eb59 | ||
|
|
554855cc7d | ||
|
|
27b471e76b | ||
|
|
00033e4af0 | ||
|
|
d327aea6ff | ||
|
|
12f44f3410 | ||
|
|
2ba9904757 | ||
|
|
255a2dbb9a | ||
|
|
ee78d6f65b | ||
|
|
328812e95b | ||
|
|
98c7887e9c | ||
|
|
5fd9317533 | ||
|
|
9787bb7ac9 | ||
|
|
201be561d4 | ||
|
|
78373d827b | ||
|
|
4e83b1642c | ||
|
|
9eef8c50c0 | ||
|
|
86e9cc3443 | ||
|
|
3ce34a0b6d | ||
|
|
187f8d625b | ||
|
|
fca64faa3c | ||
|
|
e0e3bc8994 | ||
|
|
ceae89e149 | ||
|
|
3414f72f60 | ||
|
|
d0857c49ec | ||
|
|
f59cbf0fe5 | ||
|
|
45b9ee8376 | ||
|
|
cf81ac79b3 | ||
|
|
90bb40e5ea | ||
|
|
bf268d79b4 | ||
|
|
989c992154 | ||
|
|
b1f4ad94eb | ||
|
|
547b1cfd15 | ||
|
|
9019805f52 | ||
|
|
f4fae1b9f6 | ||
|
|
094a225363 | ||
|
|
79c9c5b7f9 | ||
|
|
59a0844ee6 | ||
|
|
ed0b21beae | ||
|
|
755f23fdfa | ||
|
|
db2540485e | ||
|
|
2577afed55 | ||
|
|
2c5ebef594 | ||
|
|
913a65fde6 | ||
|
|
5218d3921a | ||
|
|
6874130743 | ||
|
|
2f3a057969 | ||
|
|
c2102f62d6 | ||
|
|
bf93040ab1 | ||
|
|
8a6abab1da | ||
|
|
005a2501b9 | ||
|
|
9508401971 | ||
|
|
89ae8b94cf | ||
|
|
a99d990117 | ||
|
|
c578e0a158 | ||
|
|
34bc6b1613 | ||
|
|
59dd6a2a56 | ||
|
|
3d388a0a96 | ||
|
|
c5813d624a | ||
|
|
3eedf4d24d | ||
|
|
3e5282bf74 | ||
|
|
ce578cafb9 | ||
|
|
12c77a228e | ||
|
|
6ab140461a | ||
|
|
18f06ea585 | ||
|
|
7fb943ae7f | ||
|
|
95f309a1c9 | ||
|
|
391d4db419 | ||
|
|
972beb52be | ||
|
|
80f22dce0b | ||
|
|
26c43d6d8b | ||
|
|
8451286c17 | ||
|
|
be5bb9e690 | ||
|
|
e6f091909b | ||
|
|
4616e2ed21 | ||
|
|
4b4efb2c07 | ||
|
|
2443d3ea47 | ||
|
|
d0c7562c41 | ||
|
|
0064097c03 | ||
|
|
8bfb965589 | ||
|
|
82c0134811 | ||
|
|
4512a0a5d7 | ||
|
|
52d2684479 | ||
|
|
7e3bf7eeb8 | ||
|
|
0753f10661 | ||
|
|
0448ce686a | ||
|
|
bedd6180f1 | ||
|
|
c6640aa7d3 | ||
|
|
7a650f940c | ||
|
|
86e1d59a6a | ||
|
|
54fa676e75 | ||
|
|
d1242a28cf | ||
|
|
ccd37d4fa3 | ||
|
|
811a9b4f89 | ||
|
|
d960a37e12 | ||
|
|
f6df075d51 | ||
|
|
c5dced237a | ||
|
|
c9c441b8bb | ||
|
|
5e2d376627 | ||
|
|
16e49eee6d | ||
|
|
70411048e5 | ||
|
|
331bcbdaf7 | ||
|
|
af03e39383 | ||
|
|
b2040d9adb | ||
|
|
cadbffe416 | ||
|
|
cd0f42804a | ||
|
|
ba4a119a4f | ||
|
|
9ff6e5caad | ||
|
|
a8bcfb998b | ||
|
|
1c39c68203 | ||
|
|
0a9b8b1318 | ||
|
|
7e075eb959 | ||
|
|
e52468e0c3 | ||
|
|
1a4798792e | ||
|
|
c4b694fdb1 | ||
|
|
75f260a941 | ||
|
|
e0409a9496 | ||
|
|
70d3cdcc08 | ||
|
|
03974481b0 | ||
|
|
58d410b1a2 | ||
|
|
38bd51e63a | ||
|
|
927362354d | ||
|
|
5bb6257acb | ||
|
|
060c0b7215 | ||
|
|
5cb527d53c | ||
|
|
cfc9ddc380 | ||
|
|
cffda88ae8 | ||
|
|
b186846a9e | ||
|
|
da2446283a | ||
|
|
6645b3f5e4 | ||
|
|
c8bd477c84 | ||
|
|
c747dc7184 | ||
|
|
9307acbe4a | ||
|
|
9106250a53 | ||
|
|
449b65cf1b | ||
|
|
0bc7b195e5 | ||
|
|
fba5676b78 | ||
|
|
14fd0296d4 |
90
.github/workflows/build.yml
vendored
90
.github/workflows/build.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
|||||||
CC: ${{ matrix.compiler }}
|
CC: ${{ matrix.compiler }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt-get install libbluetooth-dev libusb-1.0-0-dev
|
run: sudo apt-get install libbluetooth-dev libusb-1.0-0-dev
|
||||||
- run: autoreconf --install --force
|
- run: autoreconf --install --force
|
||||||
@ -30,7 +30,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
make install DESTDIR=$PWD/artifacts
|
make install DESTDIR=$PWD/artifacts
|
||||||
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
|
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ github.job }}-${{ matrix.compiler }}
|
name: ${{ github.job }}-${{ matrix.compiler }}
|
||||||
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
|
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
|
||||||
@ -50,7 +50,7 @@ jobs:
|
|||||||
CC: ${{ matrix.compiler }}
|
CC: ${{ matrix.compiler }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: brew install autoconf automake libtool hidapi libusb
|
run: brew install autoconf automake libtool hidapi libusb
|
||||||
- run: autoreconf --install --force
|
- run: autoreconf --install --force
|
||||||
@ -61,7 +61,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
make install DESTDIR=$PWD/artifacts
|
make install DESTDIR=$PWD/artifacts
|
||||||
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
|
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ github.job }}-${{ matrix.compiler }}
|
name: ${{ github.job }}-${{ matrix.compiler }}
|
||||||
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
|
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
|
||||||
@ -78,18 +78,96 @@ jobs:
|
|||||||
arch: [i686, x86_64]
|
arch: [i686, x86_64]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt-get install gcc-mingw-w64 binutils-mingw-w64 mingw-w64-tools
|
run: sudo apt-get install gcc-mingw-w64 binutils-mingw-w64 mingw-w64-tools
|
||||||
|
- name: Install libusb
|
||||||
|
env:
|
||||||
|
LIBUSB_VERSION: 1.0.26
|
||||||
|
run: |
|
||||||
|
wget -c https://github.com/libusb/libusb/archive/refs/tags/v${LIBUSB_VERSION}.tar.gz
|
||||||
|
tar xzf v${LIBUSB_VERSION}.tar.gz
|
||||||
|
pushd libusb-${LIBUSB_VERSION}
|
||||||
|
autoreconf --install --force
|
||||||
|
./configure --host=${{ matrix.arch }}-w64-mingw32 --prefix=/usr
|
||||||
|
make
|
||||||
|
make install DESTDIR=$PWD/../artifacts
|
||||||
|
popd
|
||||||
|
- name: Install hidapi
|
||||||
|
env:
|
||||||
|
HIDAPI_VERSION: 0.12.0
|
||||||
|
run: |
|
||||||
|
wget -c https://github.com/libusb/hidapi/archive/refs/tags/hidapi-${HIDAPI_VERSION}.tar.gz
|
||||||
|
tar xzf hidapi-${HIDAPI_VERSION}.tar.gz
|
||||||
|
pushd hidapi-hidapi-${HIDAPI_VERSION}
|
||||||
|
autoreconf --install --force
|
||||||
|
./configure --host=${{ matrix.arch }}-w64-mingw32 --prefix=/usr LDFLAGS='-static-libgcc'
|
||||||
|
make
|
||||||
|
make install DESTDIR=$PWD/../artifacts
|
||||||
|
popd
|
||||||
- run: autoreconf --install --force
|
- run: autoreconf --install --force
|
||||||
- run: ./configure --host=${{ matrix.arch }}-w64-mingw32 --prefix=/usr
|
- run: ./configure --host=${{ matrix.arch }}-w64-mingw32 --prefix=/usr
|
||||||
|
env:
|
||||||
|
PKG_CONFIG_LIBDIR: ${{ github.workspace }}/artifacts/usr/lib/pkgconfig
|
||||||
|
PKG_CONFIG_SYSROOT_DIR: ${{ github.workspace }}/artifacts
|
||||||
|
PKG_CONFIG_ALLOW_SYSTEM_CFLAGS: 1
|
||||||
|
PKG_CONFIG_ALLOW_SYSTEM_LIBS: 1
|
||||||
- run: make
|
- run: make
|
||||||
- run: make distcheck
|
- run: make distcheck
|
||||||
- name: Package artifacts
|
- name: Package artifacts
|
||||||
run: |
|
run: |
|
||||||
make install DESTDIR=$PWD/artifacts
|
make install DESTDIR=$PWD/artifacts
|
||||||
tar -czf ${{ github.job }}-${{ matrix.arch }}.tar.gz -C artifacts usr
|
tar -czf ${{ github.job }}-${{ matrix.arch }}.tar.gz -C artifacts usr
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ github.job }}-${{ matrix.arch }}
|
name: ${{ github.job }}-${{ matrix.arch }}
|
||||||
path: ${{ github.job }}-${{ matrix.arch }}.tar.gz
|
path: ${{ github.job }}-${{ matrix.arch }}.tar.gz
|
||||||
|
|
||||||
|
msvc:
|
||||||
|
|
||||||
|
name: Visual Studio
|
||||||
|
|
||||||
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
platform: [x86, x64]
|
||||||
|
|
||||||
|
env:
|
||||||
|
CONFIGURATION: Release
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- 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@v2
|
||||||
|
- run: msbuild -m -p:Platform=${{ matrix.platform }} -p:Configuration=${{ env.CONFIGURATION }} contrib/msvc/libdivecomputer.vcxproj
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
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@v4
|
||||||
|
- 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@v4
|
||||||
|
with:
|
||||||
|
name: ${{ github.job }}
|
||||||
|
path: contrib/android/libs
|
||||||
|
|||||||
32
.github/workflows/release.yml
vendored
32
.github/workflows/release.yml
vendored
@ -9,19 +9,13 @@ jobs:
|
|||||||
name: Release
|
name: Release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Version number
|
- name: Version number
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
VERSION="${GITHUB_REF/refs\/tags\/v/}"
|
VERSION="${GITHUB_REF/refs\/tags\/v/}"
|
||||||
if [ "${VERSION}" = "${VERSION%%-*}" ]; then
|
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||||
PRERELEASE=false
|
|
||||||
else
|
|
||||||
PRERELEASE=true
|
|
||||||
fi
|
|
||||||
echo ::set-output name=version::${VERSION}
|
|
||||||
echo ::set-output name=prerelease::${PRERELEASE}
|
|
||||||
|
|
||||||
- name: Build distribution tarball
|
- name: Build distribution tarball
|
||||||
id: build
|
id: build
|
||||||
@ -41,21 +35,13 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- uses: actions/create-release@v1
|
- name: Create Github release
|
||||||
id: release
|
id: release
|
||||||
|
run: |
|
||||||
|
VERSION="${{ steps.version.outputs.version }}"
|
||||||
|
if [ "${VERSION}" != "${VERSION%%-*}" ]; then
|
||||||
|
PRERELEASE="-p"
|
||||||
|
fi
|
||||||
|
gh release create ${PRERELEASE} "${{ github.ref }}" "libdivecomputer-${VERSION}.tar.gz"
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
|
||||||
tag_name: ${{ github.ref }}
|
|
||||||
release_name: ${{ github.ref }}
|
|
||||||
prerelease: ${{ steps.version.outputs.prerelease }}
|
|
||||||
|
|
||||||
- uses: actions/upload-release-asset@v1
|
|
||||||
id: upload
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ steps.release.outputs.upload_url }}
|
|
||||||
asset_path: libdivecomputer-${{ steps.version.outputs.version }}.tar.gz
|
|
||||||
asset_name: libdivecomputer-${{ steps.version.outputs.version }}.tar.gz
|
|
||||||
asset_content_type: application/gzip
|
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@ -47,11 +47,10 @@ Makefile.in
|
|||||||
/m4/ltsugar.m4
|
/m4/ltsugar.m4
|
||||||
/m4/ltversion.m4
|
/m4/ltversion.m4
|
||||||
|
|
||||||
/msvc/Debug/
|
/msvc/x64/
|
||||||
/msvc/Release/
|
/msvc/x86/
|
||||||
/msvc/*.ncb
|
/msvc/*.ncb
|
||||||
/msvc/*.suo
|
/msvc/*.suo
|
||||||
/msvc/*.vcproj.*.user
|
|
||||||
|
|
||||||
/src/libdivecomputer.exp
|
/src/libdivecomputer.exp
|
||||||
/src/libdivecomputer.la
|
/src/libdivecomputer.la
|
||||||
|
|||||||
@ -16,4 +16,8 @@ pkgconfig_DATA = libdivecomputer.pc
|
|||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
libdivecomputer.pc.in \
|
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
|
||||||
|
|||||||
36
NEWS
36
NEWS
@ -1,4 +1,38 @@
|
|||||||
Version 0.7.0 (2020-05-07)
|
Version 0.8.0 (2023-05-11)
|
||||||
|
==========================
|
||||||
|
|
||||||
|
The v0.8.0 release is mainly a bugfix release, and brings in support for a
|
||||||
|
number of new devices. This release is fully backwards compatible with the
|
||||||
|
previous one.
|
||||||
|
|
||||||
|
New features:
|
||||||
|
|
||||||
|
* Add support for new backends:
|
||||||
|
- excursion: Deep Six Excursion, Crest CR-4, Genesis Centauri, Tusa TC1, Scorpena Alpha
|
||||||
|
- screen: Seac Screen and Action
|
||||||
|
- cosmiq: Deepblu Cosmiq+
|
||||||
|
- s1: Oceans S1
|
||||||
|
- freedom: Divesoft Freedom and Liberty
|
||||||
|
* Add support for some new devices:
|
||||||
|
- Aqualung: i200C
|
||||||
|
- Cressi: Donatello, Michelangelo, Neon
|
||||||
|
- Mares: Puck Pro +
|
||||||
|
- Oceanic: Geo Air
|
||||||
|
- Ratio: iX3M 2
|
||||||
|
- Scubapro: G2 TEK
|
||||||
|
- Shearwater: Petrel 3, Perdix 2
|
||||||
|
- Sherwood: Amphos Air 2.0
|
||||||
|
* Add support for parsing the decompression model
|
||||||
|
* Add a public api to configure the depth calibration
|
||||||
|
* Add a public api to configure the clock synchronization
|
||||||
|
* Add a basic Android build system
|
||||||
|
|
||||||
|
Removed/changed features:
|
||||||
|
|
||||||
|
* Migrate to Visual Studio 2013 (or newer)
|
||||||
|
* Move the Visual Studio project to the contrib directory
|
||||||
|
|
||||||
|
Version 0.7.0 (2021-05-07)
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
The main highlight of the v0.7.0 release is the introduction of the new
|
The main highlight of the v0.7.0 release is the introduction of the new
|
||||||
|
|||||||
13
configure.ac
13
configure.ac
@ -1,8 +1,8 @@
|
|||||||
# Versioning.
|
# Versioning.
|
||||||
m4_define([dc_version_major],[0])
|
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_micro],[0])
|
||||||
m4_define([dc_version_suffix],[])
|
m4_define([dc_version_suffix],[devel])
|
||||||
m4_define([dc_version],dc_version_major.dc_version_minor.dc_version_micro[]m4_ifset([dc_version_suffix],-[dc_version_suffix]))
|
m4_define([dc_version],dc_version_major.dc_version_minor.dc_version_micro[]m4_ifset([dc_version_suffix],-[dc_version_suffix]))
|
||||||
|
|
||||||
# Libtool versioning.
|
# Libtool versioning.
|
||||||
@ -107,12 +107,12 @@ AS_IF([test "x$with_libusb" != "xno"], [
|
|||||||
AC_ARG_WITH([hidapi],
|
AC_ARG_WITH([hidapi],
|
||||||
[AS_HELP_STRING([--without-hidapi],
|
[AS_HELP_STRING([--without-hidapi],
|
||||||
[Build without the hidapi library])],
|
[Build without the hidapi library])],
|
||||||
[], [with_hidapi=auto])
|
[], [with_hidapi=hidapi])
|
||||||
AS_IF([test "x$with_hidapi" != "xno"], [
|
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"], [
|
AS_IF([test "x$have_hidapi" = "xyes"], [
|
||||||
AC_DEFINE([HAVE_HIDAPI], [1], [hidapi library])
|
AC_DEFINE([HAVE_HIDAPI], [1], [hidapi library])
|
||||||
DEPENDENCIES="$DEPENDENCIES hidapi"
|
DEPENDENCIES="$DEPENDENCIES $with_hidapi"
|
||||||
])
|
])
|
||||||
])
|
])
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ AC_CHECK_HEADERS([sys/socket.h linux/types.h linux/irda.h], , , [
|
|||||||
# Checks for header files.
|
# Checks for header files.
|
||||||
AC_CHECK_HEADERS([linux/serial.h])
|
AC_CHECK_HEADERS([linux/serial.h])
|
||||||
AC_CHECK_HEADERS([IOKit/serial/ioss.h])
|
AC_CHECK_HEADERS([IOKit/serial/ioss.h])
|
||||||
AC_CHECK_HEADERS([getopt.h])
|
AC_CHECK_HEADERS([unistd.h getopt.h])
|
||||||
AC_CHECK_HEADERS([sys/param.h])
|
AC_CHECK_HEADERS([sys/param.h])
|
||||||
AC_CHECK_HEADERS([pthread.h])
|
AC_CHECK_HEADERS([pthread.h])
|
||||||
AC_CHECK_HEADERS([mach/mach_time.h])
|
AC_CHECK_HEADERS([mach/mach_time.h])
|
||||||
@ -238,7 +238,6 @@ AC_CONFIG_FILES([
|
|||||||
include/libdivecomputer/Makefile
|
include/libdivecomputer/Makefile
|
||||||
include/libdivecomputer/version.h
|
include/libdivecomputer/version.h
|
||||||
src/Makefile
|
src/Makefile
|
||||||
src/libdivecomputer.rc
|
|
||||||
doc/Makefile
|
doc/Makefile
|
||||||
doc/doxygen.cfg
|
doc/doxygen.cfg
|
||||||
doc/man/Makefile
|
doc/man/Makefile
|
||||||
|
|||||||
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.
|
||||||
144
contrib/android/Android.mk
Normal file
144
contrib/android/Android.mk
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
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
|
||||||
|
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
|
# Atomic Aquatics Cobalt
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="0471", ATTR{idProduct}=="0888", GROUP="plugdev"
|
SUBSYSTEM=="usb", ATTR{idVendor}=="0471", ATTR{idProduct}=="0888", GROUP="plugdev"
|
||||||
|
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0471", ATTRS{idProduct}=="0888", GROUP="plugdev"
|
||||||
|
|
||||||
# Suunto EON Steel
|
# Suunto EON Steel
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0030", GROUP="plugdev"
|
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0030", GROUP="plugdev"
|
||||||
|
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0030", GROUP="plugdev"
|
||||||
|
|
||||||
# Suunto EON Core
|
# Suunto EON Core
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0033", GROUP="plugdev"
|
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0033", GROUP="plugdev"
|
||||||
|
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0033", GROUP="plugdev"
|
||||||
|
|
||||||
# Suunto D5
|
# Suunto D5
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0035", GROUP="plugdev"
|
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0035", GROUP="plugdev"
|
||||||
|
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0035", GROUP="plugdev"
|
||||||
|
|
||||||
|
# Suunto EON Steel Black
|
||||||
|
SUBSYSTEM=="usb", ATTR{idVendor}=="1493", ATTR{idProduct}=="0036", GROUP="plugdev"
|
||||||
|
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1493", ATTRS{idProduct}=="0036", GROUP="plugdev"
|
||||||
|
|
||||||
# Scubapro G2
|
# Scubapro G2
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3201", GROUP="plugdev"
|
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3201", GROUP="plugdev"
|
||||||
|
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2e6c", ATTRS{idProduct}=="3201", GROUP="plugdev"
|
||||||
|
|
||||||
# Scubapro G2 Console
|
# Scubapro G2 Console
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3211", GROUP="plugdev"
|
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3211", GROUP="plugdev"
|
||||||
|
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2e6c", ATTRS{idProduct}=="3211", GROUP="plugdev"
|
||||||
|
|
||||||
# Scubapro G2 HUD
|
# Scubapro G2 HUD
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="4201", GROUP="plugdev"
|
SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="4201", GROUP="plugdev"
|
||||||
|
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2e6c", ATTRS{idProduct}=="4201", GROUP="plugdev"
|
||||||
|
|
||||||
# Scubapro Aladin Square
|
# Scubapro Aladin Square
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="c251", ATTR{idProduct}=="2006", GROUP="plugdev"
|
SUBSYSTEM=="usb", ATTR{idVendor}=="c251", ATTR{idProduct}=="2006", GROUP="plugdev"
|
||||||
|
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2006", GROUP="plugdev"
|
||||||
|
|||||||
@ -32,7 +32,6 @@ MANPAGES = \
|
|||||||
dc_parser_get_field.3 \
|
dc_parser_get_field.3 \
|
||||||
dc_parser_new.3 \
|
dc_parser_new.3 \
|
||||||
dc_parser_samples_foreach.3 \
|
dc_parser_samples_foreach.3 \
|
||||||
dc_parser_set_data.3 \
|
|
||||||
dc_bluetooth_open.3 \
|
dc_bluetooth_open.3 \
|
||||||
dc_bluetooth_iterator_new.3 \
|
dc_bluetooth_iterator_new.3 \
|
||||||
dc_bluetooth_device_get_address.3 \
|
dc_bluetooth_device_get_address.3 \
|
||||||
|
|||||||
@ -82,7 +82,7 @@ is
|
|||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr dc_datetime_localtime 3 ,
|
.Xr dc_datetime_localtime 3 ,
|
||||||
.Xr dc_datetime_mktime 3 ,
|
.Xr dc_datetime_mktime 3 ,
|
||||||
.Xr dc_datetime_new 3
|
.Xr dc_datetime_now 3
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
The
|
The
|
||||||
.Lb libdivecomputer
|
.Lb libdivecomputer
|
||||||
|
|||||||
@ -82,7 +82,7 @@ is
|
|||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr dc_datetime_gmtime 3 ,
|
.Xr dc_datetime_gmtime 3 ,
|
||||||
.Xr dc_datetime_mktime 3 ,
|
.Xr dc_datetime_mktime 3 ,
|
||||||
.Xr dc_datetime_new 3
|
.Xr dc_datetime_now 3
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
The
|
The
|
||||||
.Lb libdivecomputer
|
.Lb libdivecomputer
|
||||||
|
|||||||
@ -47,7 +47,7 @@ may not sanely be converted.
|
|||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr dc_datetime_gmtime 3 ,
|
.Xr dc_datetime_gmtime 3 ,
|
||||||
.Xr dc_datetime_localtime 3 ,
|
.Xr dc_datetime_localtime 3 ,
|
||||||
.Xr dc_datetime_new 3
|
.Xr dc_datetime_now 3
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
The
|
The
|
||||||
.Lb libdivecomputer
|
.Lb libdivecomputer
|
||||||
|
|||||||
@ -53,7 +53,7 @@ with
|
|||||||
Each dive invokes
|
Each dive invokes
|
||||||
.Fa callback
|
.Fa callback
|
||||||
with the dive data, which should be parsed with
|
with the dive data, which should be parsed with
|
||||||
.Xr dc_parser_set_data 3 ,
|
.Xr dc_parser_new 3 ,
|
||||||
and the binary fingerprint of the dive.
|
and the binary fingerprint of the dive.
|
||||||
The fingerprint can be used to record the newest dive and stop
|
The fingerprint can be used to record the newest dive and stop
|
||||||
processing (on subsequent invocations) when the same dive fingerprint is
|
processing (on subsequent invocations) when the same dive fingerprint is
|
||||||
@ -72,7 +72,7 @@ If
|
|||||||
returns zero, this will not be reflected in the return value (usually
|
returns zero, this will not be reflected in the return value (usually
|
||||||
.Dv DC_STATUS_SUCCESS ) .
|
.Dv DC_STATUS_SUCCESS ) .
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr dc_parser_set_data 3
|
.Xr dc_parser_new 3
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
The
|
The
|
||||||
.Lb libdivecomputer
|
.Lb libdivecomputer
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
Extract the date and time of a dive,
|
Extract the date and time of a dive,
|
||||||
.Fa parser ,
|
.Fa parser ,
|
||||||
previously initialised with
|
previously initialised with
|
||||||
.Xr dc_parser_set_data 3 .
|
.Xr dc_parser_new 3 .
|
||||||
This returns the broken-down time-stamp of the dive in the local time of
|
This returns the broken-down time-stamp of the dive in the local time of
|
||||||
the dive.
|
the dive.
|
||||||
.Pp
|
.Pp
|
||||||
@ -57,7 +57,7 @@ messages on further failure.
|
|||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr dc_datetime_gmtime 3 ,
|
.Xr dc_datetime_gmtime 3 ,
|
||||||
.Xr dc_datetime_localtime 3 ,
|
.Xr dc_datetime_localtime 3 ,
|
||||||
.Xr dc_parser_set_data 3
|
.Xr dc_parser_new 3
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
The
|
The
|
||||||
.Lb libdivecomputer
|
.Lb libdivecomputer
|
||||||
|
|||||||
@ -39,7 +39,7 @@
|
|||||||
Extract a field from a dive,
|
Extract a field from a dive,
|
||||||
.Fa parser ,
|
.Fa parser ,
|
||||||
previously initialised with
|
previously initialised with
|
||||||
.Xr dc_parser_set_data 3 .
|
.Xr dc_parser_new 3 .
|
||||||
The
|
The
|
||||||
.Fa value
|
.Fa value
|
||||||
field type depends upon the
|
field type depends upon the
|
||||||
@ -187,7 +187,7 @@ if the field was retrieved,
|
|||||||
if the field is not supported by the device, or other error messages on
|
if the field is not supported by the device, or other error messages on
|
||||||
further failure.
|
further failure.
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr dc_parser_set_data 3
|
.Xr dc_parser_new 3
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
The
|
The
|
||||||
.Lb libdivecomputer
|
.Lb libdivecomputer
|
||||||
|
|||||||
@ -39,8 +39,6 @@
|
|||||||
.Fa "dc_parser_t **parser"
|
.Fa "dc_parser_t **parser"
|
||||||
.Fa "dc_context_t *context"
|
.Fa "dc_context_t *context"
|
||||||
.Fa "dc_descriptor_t *descriptor"
|
.Fa "dc_descriptor_t *descriptor"
|
||||||
.Fa "unsigned int devtime"
|
|
||||||
.Fa "dc_ticks_t systime"
|
|
||||||
.Fc
|
.Fc
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
Creates a parser for a single dive extracted from the dive computer with
|
Creates a parser for a single dive extracted from the dive computer with
|
||||||
@ -55,10 +53,6 @@ parameter; and
|
|||||||
.Nm dc_parser_new2 ,
|
.Nm dc_parser_new2 ,
|
||||||
which is given device values (model, etc.) directly.
|
which is given device values (model, etc.) directly.
|
||||||
.Pp
|
.Pp
|
||||||
After filling in the
|
|
||||||
.Fa parser
|
|
||||||
parameter, one usually sets parser data with
|
|
||||||
.Xr dc_parser_set_data 3 .
|
|
||||||
The pointer must later be freed with
|
The pointer must later be freed with
|
||||||
.Xr dc_parser_destroy 3 .
|
.Xr dc_parser_destroy 3 .
|
||||||
.Sh RETURN VALUES
|
.Sh RETURN VALUES
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
.Ft "typedef void"
|
.Ft "typedef void"
|
||||||
.Fo "(*dc_sample_callback_t)"
|
.Fo "(*dc_sample_callback_t)"
|
||||||
.Fa "dc_sample_type_t type"
|
.Fa "dc_sample_type_t type"
|
||||||
.Fa "dc_sample_value_t value"
|
.Fa "const dc_sample_value_t *value"
|
||||||
.Fa "void *userdata"
|
.Fa "void *userdata"
|
||||||
.Fc
|
.Fc
|
||||||
.Ft dc_status_t
|
.Ft dc_status_t
|
||||||
@ -42,7 +42,7 @@
|
|||||||
.Fc
|
.Fc
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
Extract the samples taken during a dive as previously initialised with
|
Extract the samples taken during a dive as previously initialised with
|
||||||
.Xr dc_parser_set_data 3 .
|
.Xr dc_parser_new 3 .
|
||||||
Each sample is passed to
|
Each sample is passed to
|
||||||
.Fa callback
|
.Fa callback
|
||||||
with the
|
with the
|
||||||
@ -63,7 +63,7 @@ closed.
|
|||||||
The following sample types may be raised:
|
The following sample types may be raised:
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
.It Dv DC_SAMPLE_TIME
|
.It Dv DC_SAMPLE_TIME
|
||||||
The time of the sample taken in seconds after the dive began.
|
The time of the sample taken in milliseconds after the dive began.
|
||||||
Set in the
|
Set in the
|
||||||
.Fa time
|
.Fa time
|
||||||
field.
|
field.
|
||||||
@ -184,7 +184,7 @@ Returns
|
|||||||
.Dv DC_STATUS_OK
|
.Dv DC_STATUS_OK
|
||||||
on success and another code on failure.
|
on success and another code on failure.
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr dc_parser_set_data 3
|
.Xr dc_parser_new 3
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
The
|
The
|
||||||
.Lb libdivecomputer
|
.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 .
|
.Xr dc_device_foreach 3 .
|
||||||
.It
|
.It
|
||||||
For each iterated dive, create a new parser with
|
For each iterated dive, create a new parser with
|
||||||
.Xr dc_parser_new 3
|
.Xr dc_parser_new 3 .
|
||||||
and set the parsed data with
|
|
||||||
.Xr dc_parser_set_data 3 .
|
|
||||||
.It
|
.It
|
||||||
Get attributes of the parsed dive with
|
Get attributes of the parsed dive with
|
||||||
.Xr dc_parser_get_field 3 .
|
.Xr dc_parser_get_field 3 .
|
||||||
|
|||||||
@ -72,6 +72,7 @@ static const backend_table_t g_backends[] = {
|
|||||||
{"vtpro", DC_FAMILY_OCEANIC_VTPRO, 0x4245},
|
{"vtpro", DC_FAMILY_OCEANIC_VTPRO, 0x4245},
|
||||||
{"veo250", DC_FAMILY_OCEANIC_VEO250, 0x424C},
|
{"veo250", DC_FAMILY_OCEANIC_VEO250, 0x424C},
|
||||||
{"atom2", DC_FAMILY_OCEANIC_ATOM2, 0x4342},
|
{"atom2", DC_FAMILY_OCEANIC_ATOM2, 0x4342},
|
||||||
|
{"i330r", DC_FAMILY_PELAGIC_I330R, 0x4744},
|
||||||
{"nemo", DC_FAMILY_MARES_NEMO, 0},
|
{"nemo", DC_FAMILY_MARES_NEMO, 0},
|
||||||
{"puck", DC_FAMILY_MARES_PUCK, 7},
|
{"puck", DC_FAMILY_MARES_PUCK, 7},
|
||||||
{"darwin", DC_FAMILY_MARES_DARWIN, 0},
|
{"darwin", DC_FAMILY_MARES_DARWIN, 0},
|
||||||
@ -94,6 +95,11 @@ static const backend_table_t g_backends[] = {
|
|||||||
{"extreme", DC_FAMILY_MCLEAN_EXTREME, 0},
|
{"extreme", DC_FAMILY_MCLEAN_EXTREME, 0},
|
||||||
{"lynx", DC_FAMILY_LIQUIVISION_LYNX, 0},
|
{"lynx", DC_FAMILY_LIQUIVISION_LYNX, 0},
|
||||||
{"sp2", DC_FAMILY_SPORASUB_SP2, 0},
|
{"sp2", DC_FAMILY_SPORASUB_SP2, 0},
|
||||||
|
{"excursion", DC_FAMILY_DEEPSIX_EXCURSION, 0},
|
||||||
|
{"screen", DC_FAMILY_SEAC_SCREEN, 0},
|
||||||
|
{"cosmiq", DC_FAMILY_DEEPBLU_COSMIQ, 0},
|
||||||
|
{"s1", DC_FAMILY_OCEANS_S1, 0},
|
||||||
|
{"freedom", DC_FAMILY_DIVESOFT_FREEDOM, 19},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const transport_table_t g_transports[] = {
|
static const transport_table_t g_transports[] = {
|
||||||
|
|||||||
@ -24,10 +24,12 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
@ -48,7 +50,7 @@
|
|||||||
#define RESET 1
|
#define RESET 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__GLIBC__) || defined(__MINGW32__) || defined(BSD)
|
#if defined(__GLIBC__) || defined(__MINGW32__) || defined(BSD) || defined(__ANDROID__)
|
||||||
#define NOPERMUTATION "+"
|
#define NOPERMUTATION "+"
|
||||||
#else
|
#else
|
||||||
#define NOPERMUTATION ""
|
#define NOPERMUTATION ""
|
||||||
|
|||||||
@ -24,9 +24,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
@ -78,20 +80,12 @@ dive_cb (const unsigned char *data, unsigned int size, const unsigned char *fing
|
|||||||
|
|
||||||
// Create the parser.
|
// Create the parser.
|
||||||
message ("Creating the parser.\n");
|
message ("Creating the parser.\n");
|
||||||
rc = dc_parser_new (&parser, divedata->device);
|
rc = dc_parser_new (&parser, divedata->device, data, size);
|
||||||
if (rc != DC_STATUS_SUCCESS) {
|
if (rc != DC_STATUS_SUCCESS) {
|
||||||
ERROR ("Error creating the parser.");
|
ERROR ("Error creating the parser.");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the data.
|
|
||||||
message ("Registering the data.\n");
|
|
||||||
rc = dc_parser_set_data (parser, data, size);
|
|
||||||
if (rc != DC_STATUS_SUCCESS) {
|
|
||||||
ERROR ("Error registering the data.");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the dive data.
|
// Parse the dive data.
|
||||||
message ("Parsing the dive data.\n");
|
message ("Parsing the dive data.\n");
|
||||||
rc = dctool_output_write (divedata->output, parser, data, size, fingerprint, fsize);
|
rc = dctool_output_write (divedata->output, parser, data, size, fingerprint, fsize);
|
||||||
|
|||||||
@ -24,9 +24,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -24,8 +24,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -24,8 +24,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -24,8 +24,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -24,9 +24,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
@ -52,17 +54,17 @@ parse (dc_buffer_t *buffer, dc_context_t *context, dc_descriptor_t *descriptor,
|
|||||||
|
|
||||||
// Create the parser.
|
// Create the parser.
|
||||||
message ("Creating the parser.\n");
|
message ("Creating the parser.\n");
|
||||||
rc = dc_parser_new2 (&parser, context, descriptor, devtime, systime);
|
rc = dc_parser_new2 (&parser, context, descriptor, data, size);
|
||||||
if (rc != DC_STATUS_SUCCESS) {
|
if (rc != DC_STATUS_SUCCESS) {
|
||||||
ERROR ("Error creating the parser.");
|
ERROR ("Error creating the parser.");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the data.
|
// Set the clock.
|
||||||
message ("Registering the data.\n");
|
message ("Setting the clock.\n");
|
||||||
rc = dc_parser_set_data (parser, data, size);
|
rc = dc_parser_set_clock (parser, devtime, systime);
|
||||||
if (rc != DC_STATUS_SUCCESS) {
|
if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
|
||||||
ERROR ("Error registering the data.");
|
ERROR ("Error setting the clock.");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,8 +24,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -24,8 +24,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
@ -158,7 +160,7 @@ dctool_scan_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t
|
|||||||
|
|
||||||
// Show help message.
|
// Show help message.
|
||||||
if (help) {
|
if (help) {
|
||||||
dctool_command_showhelp (&dctool_list);
|
dctool_command_showhelp (&dctool_scan);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,8 +24,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -24,8 +24,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -24,8 +24,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_GETOPT_H
|
#ifdef HAVE_GETOPT_H
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -90,7 +90,7 @@ convert_volume (double value, dctool_units_t units)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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[] = {
|
static const char *events[] = {
|
||||||
"none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter",
|
"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;
|
sample_data_t *sampledata = (sample_data_t *) userdata;
|
||||||
|
|
||||||
|
unsigned int seconds = 0, milliseconds = 0;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case DC_SAMPLE_TIME:
|
case DC_SAMPLE_TIME:
|
||||||
|
seconds = value->time / 1000;
|
||||||
|
milliseconds = value->time % 1000;
|
||||||
if (sampledata->nsamples++)
|
if (sampledata->nsamples++)
|
||||||
fprintf (sampledata->ostream, "</sample>\n");
|
fprintf (sampledata->ostream, "</sample>\n");
|
||||||
fprintf (sampledata->ostream, "<sample>\n");
|
fprintf (sampledata->ostream, "<sample>\n");
|
||||||
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;
|
break;
|
||||||
case DC_SAMPLE_DEPTH:
|
case DC_SAMPLE_DEPTH:
|
||||||
fprintf (sampledata->ostream, " <depth>%.2f</depth>\n",
|
fprintf (sampledata->ostream, " <depth>%.2f</depth>\n",
|
||||||
convert_depth(value.depth, sampledata->units));
|
convert_depth(value->depth, sampledata->units));
|
||||||
break;
|
break;
|
||||||
case DC_SAMPLE_PRESSURE:
|
case DC_SAMPLE_PRESSURE:
|
||||||
fprintf (sampledata->ostream, " <pressure tank=\"%u\">%.2f</pressure>\n",
|
fprintf (sampledata->ostream, " <pressure tank=\"%u\">%.2f</pressure>\n",
|
||||||
value.pressure.tank,
|
value->pressure.tank,
|
||||||
convert_pressure(value.pressure.value, sampledata->units));
|
convert_pressure(value->pressure.value, sampledata->units));
|
||||||
break;
|
break;
|
||||||
case DC_SAMPLE_TEMPERATURE:
|
case DC_SAMPLE_TEMPERATURE:
|
||||||
fprintf (sampledata->ostream, " <temperature>%.2f</temperature>\n",
|
fprintf (sampledata->ostream, " <temperature>%.2f</temperature>\n",
|
||||||
convert_temperature(value.temperature, sampledata->units));
|
convert_temperature(value->temperature, sampledata->units));
|
||||||
break;
|
break;
|
||||||
case DC_SAMPLE_EVENT:
|
case DC_SAMPLE_EVENT:
|
||||||
if (value.event.type != SAMPLE_EVENT_GASCHANGE && value.event.type != SAMPLE_EVENT_GASCHANGE2) {
|
if (value->event.type != SAMPLE_EVENT_GASCHANGE && value->event.type != SAMPLE_EVENT_GASCHANGE2) {
|
||||||
fprintf (sampledata->ostream, " <event type=\"%u\" time=\"%u\" flags=\"%u\" value=\"%u\">%s</event>\n",
|
fprintf (sampledata->ostream, " <event type=\"%u\" time=\"%u\" flags=\"%u\" value=\"%u\">%s</event>\n",
|
||||||
value.event.type, value.event.time, value.event.flags, value.event.value, events[value.event.type]);
|
value->event.type, value->event.time, value->event.flags, value->event.value, events[value->event.type]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DC_SAMPLE_RBT:
|
case DC_SAMPLE_RBT:
|
||||||
fprintf (sampledata->ostream, " <rbt>%u</rbt>\n", value.rbt);
|
fprintf (sampledata->ostream, " <rbt>%u</rbt>\n", value->rbt);
|
||||||
break;
|
break;
|
||||||
case DC_SAMPLE_HEARTBEAT:
|
case DC_SAMPLE_HEARTBEAT:
|
||||||
fprintf (sampledata->ostream, " <heartbeat>%u</heartbeat>\n", value.heartbeat);
|
fprintf (sampledata->ostream, " <heartbeat>%u</heartbeat>\n", value->heartbeat);
|
||||||
break;
|
break;
|
||||||
case DC_SAMPLE_BEARING:
|
case DC_SAMPLE_BEARING:
|
||||||
fprintf (sampledata->ostream, " <bearing>%u</bearing>\n", value.bearing);
|
fprintf (sampledata->ostream, " <bearing>%u</bearing>\n", value->bearing);
|
||||||
break;
|
break;
|
||||||
case DC_SAMPLE_VENDOR:
|
case DC_SAMPLE_VENDOR:
|
||||||
fprintf (sampledata->ostream, " <vendor type=\"%u\" size=\"%u\">", value.vendor.type, value.vendor.size);
|
fprintf (sampledata->ostream, " <vendor type=\"%u\" size=\"%u\">", value->vendor.type, value->vendor.size);
|
||||||
for (unsigned int i = 0; i < value.vendor.size; ++i)
|
for (unsigned int i = 0; i < value->vendor.size; ++i)
|
||||||
fprintf (sampledata->ostream, "%02X", ((const unsigned char *) value.vendor.data)[i]);
|
fprintf (sampledata->ostream, "%02X", ((const unsigned char *) value->vendor.data)[i]);
|
||||||
fprintf (sampledata->ostream, "</vendor>\n");
|
fprintf (sampledata->ostream, "</vendor>\n");
|
||||||
break;
|
break;
|
||||||
case DC_SAMPLE_SETPOINT:
|
case DC_SAMPLE_SETPOINT:
|
||||||
fprintf (sampledata->ostream, " <setpoint>%.2f</setpoint>\n", value.setpoint);
|
fprintf (sampledata->ostream, " <setpoint>%.2f</setpoint>\n", value->setpoint);
|
||||||
break;
|
break;
|
||||||
case DC_SAMPLE_PPO2:
|
case DC_SAMPLE_PPO2:
|
||||||
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;
|
break;
|
||||||
case DC_SAMPLE_CNS:
|
case DC_SAMPLE_CNS:
|
||||||
fprintf (sampledata->ostream, " <cns>%.1f</cns>\n", value.cns * 100.0);
|
fprintf (sampledata->ostream, " <cns>%.1f</cns>\n", value->cns * 100.0);
|
||||||
break;
|
break;
|
||||||
case DC_SAMPLE_DECO:
|
case DC_SAMPLE_DECO:
|
||||||
fprintf (sampledata->ostream, " <deco time=\"%u\" depth=\"%.2f\">%s</deco>\n",
|
fprintf (sampledata->ostream, " <deco time=\"%u\" depth=\"%.2f\">%s</deco>\n",
|
||||||
value.deco.time,
|
value->deco.time,
|
||||||
convert_depth(value.deco.depth, sampledata->units),
|
convert_depth(value->deco.depth, sampledata->units),
|
||||||
decostop[value.deco.type]);
|
decostop[value->deco.type]);
|
||||||
|
if (value->deco.tts) {
|
||||||
|
fprintf (sampledata->ostream, " <tts>%u</tts>\n",
|
||||||
|
value->deco.tts);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case DC_SAMPLE_GASMIX:
|
case DC_SAMPLE_GASMIX:
|
||||||
fprintf (sampledata->ostream, " <gasmix>%u</gasmix>\n", value.gasmix);
|
fprintf (sampledata->ostream, " <gasmix>%u</gasmix>\n", value->gasmix);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -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",
|
fprintf (output->ostream, "<datetime>%04i-%02i-%02i %02i:%02i:%02i %+03i:%02i</datetime>\n",
|
||||||
dt.year, dt.month, dt.day,
|
dt.year, dt.month, dt.day,
|
||||||
dt.hour, dt.minute, dt.second,
|
dt.hour, dt.minute, dt.second,
|
||||||
dt.timezone / 3600, (dt.timezone % 3600) / 60);
|
dt.timezone / 3600, (abs(dt.timezone) % 3600) / 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the divetime.
|
// Parse the divetime.
|
||||||
@ -322,11 +338,19 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
|||||||
"<gasmix>\n"
|
"<gasmix>\n"
|
||||||
" <he>%.1f</he>\n"
|
" <he>%.1f</he>\n"
|
||||||
" <o2>%.1f</o2>\n"
|
" <o2>%.1f</o2>\n"
|
||||||
" <n2>%.1f</n2>\n"
|
" <n2>%.1f</n2>\n",
|
||||||
"</gasmix>\n",
|
|
||||||
gasmix.helium * 100.0,
|
gasmix.helium * 100.0,
|
||||||
gasmix.oxygen * 100.0,
|
gasmix.oxygen * 100.0,
|
||||||
gasmix.nitrogen * 100.0);
|
gasmix.nitrogen * 100.0);
|
||||||
|
if (gasmix.usage) {
|
||||||
|
const char *usage[] = {"none", "oxygen", "diluent", "sidemount"};
|
||||||
|
fprintf (output->ostream,
|
||||||
|
" <usage>%s</usage>\n",
|
||||||
|
usage[gasmix.usage]);
|
||||||
|
}
|
||||||
|
fprintf (output->ostream,
|
||||||
|
"</gasmix>\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the tanks.
|
// Parse the tanks.
|
||||||
@ -354,6 +378,12 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
|||||||
" <gasmix>%u</gasmix>\n",
|
" <gasmix>%u</gasmix>\n",
|
||||||
tank.gasmix);
|
tank.gasmix);
|
||||||
}
|
}
|
||||||
|
if (tank.usage) {
|
||||||
|
const char *usage[] = {"none", "oxygen", "diluent", "sidemount"};
|
||||||
|
fprintf (output->ostream,
|
||||||
|
" <usage>%s</usage>\n",
|
||||||
|
usage[tank.usage]);
|
||||||
|
}
|
||||||
if (tank.type != DC_TANKVOLUME_NONE) {
|
if (tank.type != DC_TANKVOLUME_NONE) {
|
||||||
fprintf (output->ostream,
|
fprintf (output->ostream,
|
||||||
" <type>%s</type>\n"
|
" <type>%s</type>\n"
|
||||||
@ -386,6 +416,30 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
|||||||
names[divemode]);
|
names[divemode]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse the deco model.
|
||||||
|
message ("Parsing the deco model.\n");
|
||||||
|
dc_decomodel_t decomodel = {DC_DECOMODEL_NONE};
|
||||||
|
status = dc_parser_get_field (parser, DC_FIELD_DECOMODEL, 0, &decomodel);
|
||||||
|
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
|
||||||
|
ERROR ("Error parsing the deco model.");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != DC_STATUS_UNSUPPORTED) {
|
||||||
|
const char *names[] = {"none", "buhlmann", "vpm", "rgbm", "dciem"};
|
||||||
|
fprintf (output->ostream, "<decomodel>%s</decomodel>\n",
|
||||||
|
names[decomodel.type]);
|
||||||
|
if (decomodel.type == DC_DECOMODEL_BUHLMANN &&
|
||||||
|
(decomodel.params.gf.low != 0 || decomodel.params.gf.high != 0)) {
|
||||||
|
fprintf (output->ostream, "<gf>%u/%u</gf>\n",
|
||||||
|
decomodel.params.gf.low, decomodel.params.gf.high);
|
||||||
|
}
|
||||||
|
if (decomodel.conservatism) {
|
||||||
|
fprintf (output->ostream, "<conservatism>%d</conservatism>\n",
|
||||||
|
decomodel.conservatism);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Parse the salinity.
|
// Parse the salinity.
|
||||||
message ("Parsing the salinity.\n");
|
message ("Parsing the salinity.\n");
|
||||||
dc_salinity_t salinity = {DC_WATER_FRESH, 0.0};
|
dc_salinity_t salinity = {DC_WATER_FRESH, 0.0};
|
||||||
@ -396,8 +450,14 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status != DC_STATUS_UNSUPPORTED) {
|
if (status != DC_STATUS_UNSUPPORTED) {
|
||||||
fprintf (output->ostream, "<salinity type=\"%u\">%.1f</salinity>\n",
|
const char *names[] = {"fresh", "salt"};
|
||||||
salinity.type, salinity.density);
|
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.
|
// Parse the atmospheric pressure.
|
||||||
|
|||||||
@ -26,6 +26,12 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#define strcasecmp _stricmp
|
||||||
|
#define strncasecmp _strnicmp
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
|
||||||
#define FUNCTION __func__
|
#define FUNCTION __func__
|
||||||
#else
|
#else
|
||||||
|
|||||||
@ -36,9 +36,6 @@ atomics_cobalt_device_version (dc_device_t *device, unsigned char data[], unsign
|
|||||||
dc_status_t
|
dc_status_t
|
||||||
atomics_cobalt_device_set_simulation (dc_device_t *device, unsigned int simulation);
|
atomics_cobalt_device_set_simulation (dc_device_t *device, unsigned int simulation);
|
||||||
|
|
||||||
dc_status_t
|
|
||||||
atomics_cobalt_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
@ -33,6 +33,21 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
#define DC_IOCTL_BLE_GET_NAME DC_IOCTL_IOR('b', 0, DC_IOCTL_SIZE_VARIABLE)
|
#define DC_IOCTL_BLE_GET_NAME DC_IOCTL_IOR('b', 0, DC_IOCTL_SIZE_VARIABLE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the bluetooth authentication PIN code.
|
||||||
|
*
|
||||||
|
* The data format is a NULL terminated string.
|
||||||
|
*/
|
||||||
|
#define DC_IOCTL_BLE_GET_PINCODE DC_IOCTL_IOR('b', 1, DC_IOCTL_SIZE_VARIABLE)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get/set the bluetooth authentication access code.
|
||||||
|
*
|
||||||
|
* The data format is a variable sized byte array.
|
||||||
|
*/
|
||||||
|
#define DC_IOCTL_BLE_GET_ACCESSCODE DC_IOCTL_IOR('b', 2, DC_IOCTL_SIZE_VARIABLE)
|
||||||
|
#define DC_IOCTL_BLE_SET_ACCESSCODE DC_IOCTL_IOW('b', 2, DC_IOCTL_SIZE_VARIABLE)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
@ -74,6 +74,7 @@ typedef enum dc_family_t {
|
|||||||
DC_FAMILY_OCEANIC_VTPRO = (4 << 16),
|
DC_FAMILY_OCEANIC_VTPRO = (4 << 16),
|
||||||
DC_FAMILY_OCEANIC_VEO250,
|
DC_FAMILY_OCEANIC_VEO250,
|
||||||
DC_FAMILY_OCEANIC_ATOM2,
|
DC_FAMILY_OCEANIC_ATOM2,
|
||||||
|
DC_FAMILY_PELAGIC_I330R,
|
||||||
/* Mares */
|
/* Mares */
|
||||||
DC_FAMILY_MARES_NEMO = (5 << 16),
|
DC_FAMILY_MARES_NEMO = (5 << 16),
|
||||||
DC_FAMILY_MARES_PUCK,
|
DC_FAMILY_MARES_PUCK,
|
||||||
@ -110,6 +111,16 @@ typedef enum dc_family_t {
|
|||||||
DC_FAMILY_LIQUIVISION_LYNX = (17 << 16),
|
DC_FAMILY_LIQUIVISION_LYNX = (17 << 16),
|
||||||
/* Sporasub */
|
/* Sporasub */
|
||||||
DC_FAMILY_SPORASUB_SP2 = (18 << 16),
|
DC_FAMILY_SPORASUB_SP2 = (18 << 16),
|
||||||
|
/* Deep Six */
|
||||||
|
DC_FAMILY_DEEPSIX_EXCURSION = (19 << 16),
|
||||||
|
/* Seac Screen */
|
||||||
|
DC_FAMILY_SEAC_SCREEN = (20 << 16),
|
||||||
|
/* Deepblu Cosmiq */
|
||||||
|
DC_FAMILY_DEEPBLU_COSMIQ = (21 << 16),
|
||||||
|
/* Oceans S1 */
|
||||||
|
DC_FAMILY_OCEANS_S1 = (22 << 16),
|
||||||
|
/* Divesoft Freedom */
|
||||||
|
DC_FAMILY_DIVESOFT_FREEDOM = (23 << 16),
|
||||||
} dc_family_t;
|
} dc_family_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@ -29,29 +29,96 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opaque object representing a supported dive computer.
|
||||||
|
*/
|
||||||
typedef struct dc_descriptor_t dc_descriptor_t;
|
typedef struct dc_descriptor_t dc_descriptor_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an iterator to enumerate the supported dive computers.
|
||||||
|
*
|
||||||
|
* @param[out] iterator A location to store the iterator.
|
||||||
|
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
|
||||||
|
* on failure.
|
||||||
|
*/
|
||||||
dc_status_t
|
dc_status_t
|
||||||
dc_descriptor_iterator (dc_iterator_t **iterator);
|
dc_descriptor_iterator (dc_iterator_t **iterator);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free the device descriptor.
|
||||||
|
*
|
||||||
|
* @param[in] descriptor A valid device descriptor.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
dc_descriptor_free (dc_descriptor_t *descriptor);
|
dc_descriptor_free (dc_descriptor_t *descriptor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the vendor name of the dive computer.
|
||||||
|
*
|
||||||
|
* @param[in] descriptor A valid device descriptor.
|
||||||
|
* @returns The vendor name of the dive computer on success, or NULL on failure.
|
||||||
|
*/
|
||||||
const char *
|
const char *
|
||||||
dc_descriptor_get_vendor (dc_descriptor_t *descriptor);
|
dc_descriptor_get_vendor (dc_descriptor_t *descriptor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the product name of the dive computer.
|
||||||
|
*
|
||||||
|
* @param[in] descriptor A valid device descriptor.
|
||||||
|
* @returns The product name of the dive computer on success, or NULL on
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
const char *
|
const char *
|
||||||
dc_descriptor_get_product (dc_descriptor_t *descriptor);
|
dc_descriptor_get_product (dc_descriptor_t *descriptor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the family type of the dive computer.
|
||||||
|
*
|
||||||
|
* @param[in] descriptor A valid device descriptor.
|
||||||
|
* @returns The family type of the dive computer on success, or DC_FAMILY_NULL
|
||||||
|
* on failure.
|
||||||
|
*/
|
||||||
dc_family_t
|
dc_family_t
|
||||||
dc_descriptor_get_type (dc_descriptor_t *descriptor);
|
dc_descriptor_get_type (dc_descriptor_t *descriptor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the model number of the dive computer.
|
||||||
|
*
|
||||||
|
* @param[in] descriptor A valid device descriptor.
|
||||||
|
* @returns The model number of the dive computer on success, or zero on
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
unsigned int
|
unsigned int
|
||||||
dc_descriptor_get_model (dc_descriptor_t *descriptor);
|
dc_descriptor_get_model (dc_descriptor_t *descriptor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all transports supported by the dive computer.
|
||||||
|
*
|
||||||
|
* @param[in] descriptor A valid device descriptor.
|
||||||
|
* @returns A bitmask with all the transports supported by the dive computer on
|
||||||
|
* success, or DC_TRANSPORT_NONE on failure.
|
||||||
|
*/
|
||||||
unsigned int
|
unsigned int
|
||||||
dc_descriptor_get_transports (dc_descriptor_t *descriptor);
|
dc_descriptor_get_transports (dc_descriptor_t *descriptor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a low-level I/O device matches a supported dive computer.
|
||||||
|
*
|
||||||
|
* @param[in] descriptor A valid device descriptor.
|
||||||
|
* @param[in] transport The transport type of the I/O device.
|
||||||
|
* @param[in] userdata A pointer to a transport specific data structure:
|
||||||
|
* - DC_TRANSPORT_SERIAL: Name of the device node (string)
|
||||||
|
* - DC_TRANSPORT_USB: USB VID/PID (#dc_usb_desc_t)
|
||||||
|
* - DC_TRANSPORT_USBHID: USB VID/PID (#dc_usbhid_desc_t)
|
||||||
|
* - DC_TRANSPORT_IRDA: IrDA device name (string)
|
||||||
|
* - DC_TRANSPORT_BLUETOOTH: Bluetooth device name (string)
|
||||||
|
* - DC_TRANSPORT_BLE: Bluetooth device name (string)
|
||||||
|
* @returns Non-zero if the device matches a supported dive computer, or zero if
|
||||||
|
* there is no match.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
@ -62,7 +62,8 @@ typedef enum dc_field_type_t {
|
|||||||
DC_FIELD_TEMPERATURE_MAXIMUM,
|
DC_FIELD_TEMPERATURE_MAXIMUM,
|
||||||
DC_FIELD_TANK_COUNT,
|
DC_FIELD_TANK_COUNT,
|
||||||
DC_FIELD_TANK,
|
DC_FIELD_TANK,
|
||||||
DC_FIELD_DIVEMODE
|
DC_FIELD_DIVEMODE,
|
||||||
|
DC_FIELD_DECOMODEL,
|
||||||
} dc_field_type_t;
|
} dc_field_type_t;
|
||||||
|
|
||||||
typedef enum parser_sample_event_t {
|
typedef enum parser_sample_event_t {
|
||||||
@ -140,12 +141,21 @@ typedef struct dc_salinity_t {
|
|||||||
double density;
|
double density;
|
||||||
} dc_salinity_t;
|
} dc_salinity_t;
|
||||||
|
|
||||||
|
typedef enum dc_usage_t {
|
||||||
|
DC_USAGE_NONE,
|
||||||
|
DC_USAGE_OXYGEN,
|
||||||
|
DC_USAGE_DILUENT,
|
||||||
|
DC_USAGE_SIDEMOUNT,
|
||||||
|
} dc_usage_t;
|
||||||
|
|
||||||
typedef struct dc_gasmix_t {
|
typedef struct dc_gasmix_t {
|
||||||
double helium;
|
double helium;
|
||||||
double oxygen;
|
double oxygen;
|
||||||
double nitrogen;
|
double nitrogen;
|
||||||
|
dc_usage_t usage;
|
||||||
} dc_gasmix_t;
|
} dc_gasmix_t;
|
||||||
|
|
||||||
|
#define DC_SENSOR_NONE 0xFFFFFFFF
|
||||||
#define DC_GASMIX_UNKNOWN 0xFFFFFFFF
|
#define DC_GASMIX_UNKNOWN 0xFFFFFFFF
|
||||||
|
|
||||||
typedef enum dc_tankvolume_t {
|
typedef enum dc_tankvolume_t {
|
||||||
@ -184,10 +194,48 @@ typedef struct dc_tank_t {
|
|||||||
double workpressure; /* Work pressure (bar) */
|
double workpressure; /* Work pressure (bar) */
|
||||||
double beginpressure; /* Begin pressure (bar) */
|
double beginpressure; /* Begin pressure (bar) */
|
||||||
double endpressure; /* End pressure (bar) */
|
double endpressure; /* End pressure (bar) */
|
||||||
|
dc_usage_t usage;
|
||||||
} dc_tank_t;
|
} dc_tank_t;
|
||||||
|
|
||||||
|
typedef enum dc_decomodel_type_t {
|
||||||
|
DC_DECOMODEL_NONE,
|
||||||
|
DC_DECOMODEL_BUHLMANN,
|
||||||
|
DC_DECOMODEL_VPM,
|
||||||
|
DC_DECOMODEL_RGBM,
|
||||||
|
DC_DECOMODEL_DCIEM,
|
||||||
|
} dc_decomodel_type_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Decompression model
|
||||||
|
*
|
||||||
|
* The type field contains the decompression algorithm.
|
||||||
|
*
|
||||||
|
* The (optional) conservatism field contains the personal adjustment
|
||||||
|
* setting of the algorithm. The exact interpretation depends on the
|
||||||
|
* dive computer, but the default value (zero) will typically correspond
|
||||||
|
* to the neutral setting, while a positive value is more conservative
|
||||||
|
* and a negative value more aggressive.
|
||||||
|
*
|
||||||
|
* The (optional) params field contains the parameters of the algorithm:
|
||||||
|
*
|
||||||
|
* DC_DECOMODEL_BUHLMANN: The Gradient Factor (GF) parameters low and
|
||||||
|
* high. For a pure Buhlmann algorithm (e.g. without GF enabled), both
|
||||||
|
* values are 100. If GF are enabled, but the actual parameter values
|
||||||
|
* are not available from the dive computer, both values are zero.
|
||||||
|
*/
|
||||||
|
typedef struct dc_decomodel_t {
|
||||||
|
dc_decomodel_type_t type;
|
||||||
|
int conservatism;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
unsigned int high;
|
||||||
|
unsigned int low;
|
||||||
|
} gf;
|
||||||
|
} params;
|
||||||
|
} dc_decomodel_t;
|
||||||
|
|
||||||
typedef union dc_sample_value_t {
|
typedef union dc_sample_value_t {
|
||||||
unsigned int time;
|
unsigned int time; /* Milliseconds */
|
||||||
double depth;
|
double depth;
|
||||||
struct {
|
struct {
|
||||||
unsigned int tank;
|
unsigned int tank;
|
||||||
@ -209,31 +257,41 @@ typedef union dc_sample_value_t {
|
|||||||
const void *data;
|
const void *data;
|
||||||
} vendor;
|
} vendor;
|
||||||
double setpoint;
|
double setpoint;
|
||||||
double ppo2;
|
struct {
|
||||||
|
unsigned int sensor;
|
||||||
|
double value;
|
||||||
|
} ppo2;
|
||||||
double cns;
|
double cns;
|
||||||
struct {
|
struct {
|
||||||
unsigned int type;
|
unsigned int type;
|
||||||
unsigned int time;
|
unsigned int time;
|
||||||
double depth;
|
double depth;
|
||||||
|
unsigned int tts;
|
||||||
} deco;
|
} deco;
|
||||||
unsigned int gasmix; /* Gas mix index */
|
unsigned int gasmix; /* Gas mix index */
|
||||||
} dc_sample_value_t;
|
} dc_sample_value_t;
|
||||||
|
|
||||||
typedef struct dc_parser_t dc_parser_t;
|
typedef struct dc_parser_t dc_parser_t;
|
||||||
|
|
||||||
typedef void (*dc_sample_callback_t) (dc_sample_type_t type, 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_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_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_family_t
|
||||||
dc_parser_get_type (dc_parser_t *parser);
|
dc_parser_get_type (dc_parser_t *parser);
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
dc_parser_set_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_status_t
|
||||||
dc_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime);
|
dc_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime);
|
||||||
|
|||||||
@ -35,9 +35,6 @@ extern "C" {
|
|||||||
dc_status_t
|
dc_status_t
|
||||||
reefnet_sensus_device_get_handshake (dc_device_t *device, unsigned char data[], unsigned int size);
|
reefnet_sensus_device_get_handshake (dc_device_t *device, unsigned char data[], unsigned int size);
|
||||||
|
|
||||||
dc_status_t
|
|
||||||
reefnet_sensus_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
@ -38,9 +38,6 @@ reefnet_sensuspro_device_get_handshake (dc_device_t *device, unsigned char data[
|
|||||||
dc_status_t
|
dc_status_t
|
||||||
reefnet_sensuspro_device_write_interval (dc_device_t *device, unsigned char interval);
|
reefnet_sensuspro_device_write_interval (dc_device_t *device, unsigned char interval);
|
||||||
|
|
||||||
dc_status_t
|
|
||||||
reefnet_sensuspro_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
@ -56,9 +56,6 @@ reefnet_sensusultra_device_write_parameter (dc_device_t *device, reefnet_sensusu
|
|||||||
dc_status_t
|
dc_status_t
|
||||||
reefnet_sensusultra_device_sense (dc_device_t *device, unsigned char data[], unsigned int size);
|
reefnet_sensusultra_device_sense (dc_device_t *device, unsigned char data[], unsigned int size);
|
||||||
|
|
||||||
dc_status_t
|
|
||||||
reefnet_sensusultra_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
@ -86,6 +86,14 @@ typedef enum dc_usb_recipient_t {
|
|||||||
DC_USB_RECIPIENT_OTHER = 0x03,
|
DC_USB_RECIPIENT_OTHER = 0x03,
|
||||||
} dc_usb_recipient_t;
|
} dc_usb_recipient_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* USB device descriptor.
|
||||||
|
*/
|
||||||
|
typedef struct dc_usb_desc_t {
|
||||||
|
unsigned short vid;
|
||||||
|
unsigned short pid;
|
||||||
|
} dc_usb_desc_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opaque object representing a USB device.
|
* Opaque object representing a USB device.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -32,6 +32,14 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* USB HID device descriptor.
|
||||||
|
*/
|
||||||
|
typedef struct dc_usbhid_desc_t {
|
||||||
|
unsigned short vid;
|
||||||
|
unsigned short pid;
|
||||||
|
} dc_usbhid_desc_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opaque object representing a USB HID device.
|
* Opaque object representing a USB HID device.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,959 +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\platform.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\sporasub_sp2.c"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\src\sporasub_sp2_parser.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\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\sporasub_sp2.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\timer.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\include\libdivecomputer\units.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\include\libdivecomputer\usb.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\include\libdivecomputer\usbhid.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\src\uwatec_aladin.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\src\uwatec_memomouse.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\src\uwatec_smart.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\include\libdivecomputer\version.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\src\zeagle_n2ition3.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
<Filter
|
|
||||||
Name="Resource Files"
|
|
||||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
|
||||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath="..\src\libdivecomputer.rc"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\src\libdivecomputer.symbols"
|
|
||||||
>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
CommandLine="echo EXPORTS > "$(OutDir)/libdivecomputer.def" && type "$(InputPath)" >> "$(OutDir)/libdivecomputer.def""
|
|
||||||
Outputs="$(OutDir)/libdivecomputer.def"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCustomBuildTool"
|
|
||||||
CommandLine="echo EXPORTS > "$(OutDir)/libdivecomputer.def" && type "$(InputPath)" >> "$(OutDir)/libdivecomputer.def""
|
|
||||||
Outputs="$(OutDir)/libdivecomputer.def"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
</Files>
|
|
||||||
<Globals>
|
|
||||||
</Globals>
|
|
||||||
</VisualStudioProject>
|
|
||||||
@ -16,7 +16,7 @@ endif
|
|||||||
|
|
||||||
libdivecomputer_la_SOURCES = \
|
libdivecomputer_la_SOURCES = \
|
||||||
version.c \
|
version.c \
|
||||||
descriptor-private.h descriptor.c \
|
descriptor.c \
|
||||||
iostream-private.h iostream.c \
|
iostream-private.h iostream.c \
|
||||||
iterator-private.h iterator.c \
|
iterator-private.h iterator.c \
|
||||||
common-private.h common.c \
|
common-private.h common.c \
|
||||||
@ -43,6 +43,7 @@ libdivecomputer_la_SOURCES = \
|
|||||||
oceanic_atom2.h oceanic_atom2.c oceanic_atom2_parser.c \
|
oceanic_atom2.h oceanic_atom2.c oceanic_atom2_parser.c \
|
||||||
oceanic_veo250.h oceanic_veo250.c oceanic_veo250_parser.c \
|
oceanic_veo250.h oceanic_veo250.c oceanic_veo250_parser.c \
|
||||||
oceanic_vtpro.h oceanic_vtpro.c oceanic_vtpro_parser.c \
|
oceanic_vtpro.h oceanic_vtpro.c oceanic_vtpro_parser.c \
|
||||||
|
pelagic_i330r.h pelagic_i330r.c \
|
||||||
mares_common.h mares_common.c \
|
mares_common.h mares_common.c \
|
||||||
mares_nemo.h mares_nemo.c mares_nemo_parser.c \
|
mares_nemo.h mares_nemo.c mares_nemo_parser.c \
|
||||||
mares_puck.h mares_puck.c \
|
mares_puck.h mares_puck.c \
|
||||||
@ -75,6 +76,14 @@ libdivecomputer_la_SOURCES = \
|
|||||||
mclean_extreme.h mclean_extreme.c mclean_extreme_parser.c \
|
mclean_extreme.h mclean_extreme.c mclean_extreme_parser.c \
|
||||||
liquivision_lynx.h liquivision_lynx.c liquivision_lynx_parser.c \
|
liquivision_lynx.h liquivision_lynx.c liquivision_lynx_parser.c \
|
||||||
sporasub_sp2.h sporasub_sp2.c sporasub_sp2_parser.c \
|
sporasub_sp2.h sporasub_sp2.c sporasub_sp2_parser.c \
|
||||||
|
deepsix_excursion.h deepsix_excursion.c deepsix_excursion_parser.c \
|
||||||
|
seac_screen.h seac_screen.c seac_screen_parser.c \
|
||||||
|
deepblu_cosmiq.h deepblu_cosmiq.c deepblu_cosmiq_parser.c \
|
||||||
|
oceans_s1_common.h oceans_s1_common.c \
|
||||||
|
oceans_s1.h oceans_s1.c oceans_s1_parser.c \
|
||||||
|
divesoft_freedom.h divesoft_freedom.c divesoft_freedom_parser.c \
|
||||||
|
hdlc.h hdlc.c \
|
||||||
|
packet.h packet.c \
|
||||||
socket.h socket.c \
|
socket.h socket.c \
|
||||||
irda.c \
|
irda.c \
|
||||||
usb.c \
|
usb.c \
|
||||||
@ -98,7 +107,7 @@ libdivecomputer.exp: libdivecomputer.symbols
|
|||||||
$(AM_V_GEN) sed -e '/^$$/d' $< > $@
|
$(AM_V_GEN) sed -e '/^$$/d' $< > $@
|
||||||
|
|
||||||
.rc.lo:
|
.rc.lo:
|
||||||
$(AM_V_GEN) $(LIBTOOL) --silent --tag=CC --mode=compile $(RC) $(DEFS) $(DEFAULT_INCLUDES) $< -o $@
|
$(AM_V_GEN) $(LIBTOOL) --silent --tag=CC --mode=compile $(RC) $(DEFS) $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $< -o $@
|
||||||
|
|
||||||
libdivecomputer.lo: revision.h
|
libdivecomputer.lo: revision.h
|
||||||
|
|
||||||
|
|||||||
187
src/array.c
187
src/array.c
@ -160,6 +160,30 @@ array_convert_str2num (const unsigned char data[], unsigned int size)
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
array_convert_bin2dec (const unsigned char data[], unsigned int size)
|
||||||
|
{
|
||||||
|
unsigned int value = 0;
|
||||||
|
for (unsigned int i = 0; i < size; ++i) {
|
||||||
|
value *= 100;
|
||||||
|
value += data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
array_convert_bcd2dec (const unsigned char data[], unsigned int size)
|
||||||
|
{
|
||||||
|
unsigned int value = 0;
|
||||||
|
for (unsigned int i = 0; i < size; ++i) {
|
||||||
|
value *= 100;
|
||||||
|
value += bcd2dec(data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
array_uint_be (const unsigned char data[], unsigned int n)
|
array_uint_be (const unsigned char data[], unsigned int n)
|
||||||
{
|
{
|
||||||
@ -184,6 +208,32 @@ array_uint_le (const unsigned char data[], unsigned int n)
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long long
|
||||||
|
array_uint64_be (const unsigned char data[])
|
||||||
|
{
|
||||||
|
return ((unsigned long long) data[0] << 56) |
|
||||||
|
((unsigned long long) data[1] << 48) |
|
||||||
|
((unsigned long long) data[2] << 40) |
|
||||||
|
((unsigned long long) data[3] << 32) |
|
||||||
|
((unsigned long long) data[4] << 24) |
|
||||||
|
((unsigned long long) data[5] << 16) |
|
||||||
|
((unsigned long long) data[6] << 8) |
|
||||||
|
((unsigned long long) data[7] << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long
|
||||||
|
array_uint64_le (const unsigned char data[])
|
||||||
|
{
|
||||||
|
return ((unsigned long long) data[0] << 0) |
|
||||||
|
((unsigned long long) data[1] << 8) |
|
||||||
|
((unsigned long long) data[2] << 16) |
|
||||||
|
((unsigned long long) data[3] << 24) |
|
||||||
|
((unsigned long long) data[4] << 32) |
|
||||||
|
((unsigned long long) data[5] << 40) |
|
||||||
|
((unsigned long long) data[6] << 48) |
|
||||||
|
((unsigned long long) data[7] << 56);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
array_uint32_be (const unsigned char data[])
|
array_uint32_be (const unsigned char data[])
|
||||||
{
|
{
|
||||||
@ -213,17 +263,6 @@ array_uint32_word_be (const unsigned char data[])
|
|||||||
((unsigned int) data[3] << 16);
|
((unsigned int) data[3] << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
array_uint32_le_set (unsigned char data[], const unsigned int input)
|
|
||||||
{
|
|
||||||
data[0] = input & 0xFF;
|
|
||||||
data[1] = (input >> 8) & 0xFF;
|
|
||||||
data[2] = (input >> 16) & 0xFF;
|
|
||||||
data[3] = (input >> 24) & 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
array_uint24_be (const unsigned char data[])
|
array_uint24_be (const unsigned char data[])
|
||||||
{
|
{
|
||||||
@ -232,16 +271,6 @@ array_uint24_be (const unsigned char data[])
|
|||||||
((unsigned int) data[2] << 0);
|
((unsigned int) data[2] << 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
array_uint24_be_set (unsigned char data[], const unsigned int input)
|
|
||||||
{
|
|
||||||
data[0] = (input >> 16) & 0xFF;
|
|
||||||
data[1] = (input >> 8) & 0xFF;
|
|
||||||
data[2] = input & 0xFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
array_uint24_le (const unsigned char data[])
|
array_uint24_le (const unsigned char data[])
|
||||||
{
|
{
|
||||||
@ -265,8 +294,124 @@ array_uint16_le (const unsigned char data[])
|
|||||||
((unsigned int) data[1] << 8);
|
((unsigned int) data[1] << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint64_be_set (unsigned char data[], const unsigned long long input)
|
||||||
|
{
|
||||||
|
data[0] = (input >> 56) & 0xFF;
|
||||||
|
data[1] = (input >> 48) & 0xFF;
|
||||||
|
data[2] = (input >> 40) & 0xFF;
|
||||||
|
data[3] = (input >> 32) & 0xFF;
|
||||||
|
data[4] = (input >> 24) & 0xFF;
|
||||||
|
data[5] = (input >> 16) & 0xFF;
|
||||||
|
data[6] = (input >> 8) & 0xFF;
|
||||||
|
data[7] = (input ) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint64_le_set (unsigned char data[], const unsigned long long input)
|
||||||
|
{
|
||||||
|
data[0] = (input ) & 0xFF;
|
||||||
|
data[1] = (input >> 8) & 0xFF;
|
||||||
|
data[2] = (input >> 16) & 0xFF;
|
||||||
|
data[3] = (input >> 24) & 0xFF;
|
||||||
|
data[4] = (input >> 32) & 0xFF;
|
||||||
|
data[5] = (input >> 40) & 0xFF;
|
||||||
|
data[6] = (input >> 48) & 0xFF;
|
||||||
|
data[7] = (input >> 56) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint32_be_set (unsigned char data[], const unsigned int input)
|
||||||
|
{
|
||||||
|
data[0] = (input >> 24) & 0xFF;
|
||||||
|
data[1] = (input >> 16) & 0xFF;
|
||||||
|
data[2] = (input >> 8) & 0xFF;
|
||||||
|
data[3] = (input ) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint32_le_set (unsigned char data[], const unsigned int input)
|
||||||
|
{
|
||||||
|
data[0] = (input ) & 0xFF;
|
||||||
|
data[1] = (input >> 8) & 0xFF;
|
||||||
|
data[2] = (input >> 16) & 0xFF;
|
||||||
|
data[3] = (input >> 24) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint24_be_set (unsigned char data[], const unsigned int input)
|
||||||
|
{
|
||||||
|
data[0] = (input >> 16) & 0xFF;
|
||||||
|
data[1] = (input >> 8) & 0xFF;
|
||||||
|
data[2] = (input ) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint24_le_set (unsigned char data[], const unsigned int input)
|
||||||
|
{
|
||||||
|
data[0] = (input ) & 0xFF;
|
||||||
|
data[1] = (input >> 8) & 0xFF;
|
||||||
|
data[2] = (input >> 16) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint16_be_set (unsigned char data[], const unsigned short input)
|
||||||
|
{
|
||||||
|
data[0] = (input >> 8) & 0xFF;
|
||||||
|
data[1] = (input ) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint16_le_set (unsigned char data[], const unsigned short input)
|
||||||
|
{
|
||||||
|
data[0] = (input ) & 0xFF;
|
||||||
|
data[1] = (input >> 8) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char
|
unsigned char
|
||||||
bcd2dec (unsigned char value)
|
bcd2dec (unsigned char value)
|
||||||
{
|
{
|
||||||
return ((value >> 4) & 0x0f) * 10 + (value & 0x0f);
|
return ((value >> 4) & 0x0f) * 10 + (value & 0x0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned char
|
||||||
|
dec2bcd (unsigned char value)
|
||||||
|
{
|
||||||
|
if (value >= 100)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
unsigned char hi = value / 10;
|
||||||
|
unsigned char lo = value % 10;
|
||||||
|
return (hi << 4) | lo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When turning a two's-complement number with a certain number
|
||||||
|
* of bits into one with more bits, the sign bit must be repeated
|
||||||
|
* in all the extra bits.
|
||||||
|
*/
|
||||||
|
unsigned int
|
||||||
|
signextend (unsigned int value, unsigned int nbits)
|
||||||
|
{
|
||||||
|
if (nbits <= 0 || nbits > 32)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
unsigned int signbit = 1U << (nbits - 1);
|
||||||
|
unsigned int mask = signbit - 1;
|
||||||
|
|
||||||
|
if ((value & signbit) == signbit)
|
||||||
|
return value | ~mask;
|
||||||
|
else
|
||||||
|
return value & mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
popcount (unsigned int value)
|
||||||
|
{
|
||||||
|
unsigned int count = 0;
|
||||||
|
while (value) {
|
||||||
|
value &= value - 1;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|||||||
53
src/array.h
53
src/array.h
@ -22,6 +22,8 @@
|
|||||||
#ifndef ARRAY_H
|
#ifndef ARRAY_H
|
||||||
#define ARRAY_H
|
#define ARRAY_H
|
||||||
|
|
||||||
|
#define C_ARRAY_SIZE(a) (sizeof (a) / sizeof *(a))
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
@ -52,12 +54,24 @@ array_convert_hex2bin (const unsigned char input[], unsigned int isize, unsigned
|
|||||||
unsigned int
|
unsigned int
|
||||||
array_convert_str2num (const unsigned char data[], unsigned int size);
|
array_convert_str2num (const unsigned char data[], unsigned int size);
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
array_convert_bin2dec (const unsigned char data[], unsigned int size);
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
array_convert_bcd2dec (const unsigned char data[], unsigned int size);
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
array_uint_be (const unsigned char data[], unsigned int n);
|
array_uint_be (const unsigned char data[], unsigned int n);
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
array_uint_le (const unsigned char data[], unsigned int n);
|
array_uint_le (const unsigned char data[], unsigned int n);
|
||||||
|
|
||||||
|
unsigned long long
|
||||||
|
array_uint64_be (const unsigned char data[]);
|
||||||
|
|
||||||
|
unsigned long long
|
||||||
|
array_uint64_le (const unsigned char data[]);
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
array_uint32_be (const unsigned char data[]);
|
array_uint32_be (const unsigned char data[]);
|
||||||
|
|
||||||
@ -67,15 +81,9 @@ array_uint32_le (const unsigned char data[]);
|
|||||||
unsigned int
|
unsigned int
|
||||||
array_uint32_word_be (const unsigned char data[]);
|
array_uint32_word_be (const unsigned char data[]);
|
||||||
|
|
||||||
void
|
|
||||||
array_uint32_le_set (unsigned char data[], const unsigned int input);
|
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
array_uint24_be (const unsigned char data[]);
|
array_uint24_be (const unsigned char data[]);
|
||||||
|
|
||||||
void
|
|
||||||
array_uint24_be_set (unsigned char data[], const unsigned int input);
|
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
array_uint24_le (const unsigned char data[]);
|
array_uint24_le (const unsigned char data[]);
|
||||||
|
|
||||||
@ -85,9 +93,42 @@ array_uint16_be (const unsigned char data[]);
|
|||||||
unsigned short
|
unsigned short
|
||||||
array_uint16_le (const unsigned char data[]);
|
array_uint16_le (const unsigned char data[]);
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint64_be_set (unsigned char data[], const unsigned long long input);
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint64_le_set (unsigned char data[], const unsigned long long input);
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint32_be_set (unsigned char data[], const unsigned int input);
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint32_le_set (unsigned char data[], const unsigned int input);
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint24_be_set (unsigned char data[], const unsigned int input);
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint24_le_set (unsigned char data[], const unsigned int input);
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint16_be_set (unsigned char data[], const unsigned short input);
|
||||||
|
|
||||||
|
void
|
||||||
|
array_uint16_le_set (unsigned char data[], const unsigned short input);
|
||||||
|
|
||||||
unsigned char
|
unsigned char
|
||||||
bcd2dec (unsigned char value);
|
bcd2dec (unsigned char value);
|
||||||
|
|
||||||
|
unsigned char
|
||||||
|
dec2bcd (unsigned char value);
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
signextend (unsigned int value, unsigned int nbits);
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
popcount (unsigned int value);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
@ -41,6 +41,8 @@
|
|||||||
|
|
||||||
#define FP_OFFSET 20
|
#define FP_OFFSET 20
|
||||||
|
|
||||||
|
#define SZ_HEADER 228
|
||||||
|
|
||||||
#define SZ_MEMORY1 (29 * 64 * 1024) // Cobalt 1
|
#define SZ_MEMORY1 (29 * 64 * 1024) // Cobalt 1
|
||||||
#define SZ_MEMORY2 (41 * 64 * 1024) // Cobalt 2
|
#define SZ_MEMORY2 (41 * 64 * 1024) // Cobalt 2
|
||||||
#define SZ_VERSION 14
|
#define SZ_VERSION 14
|
||||||
@ -347,6 +349,12 @@ atomics_cobalt_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
|
|||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (size < SZ_HEADER) {
|
||||||
|
ERROR (abstract->context, "Dive header is too small (%u).", size);
|
||||||
|
dc_buffer_free (buffer);
|
||||||
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
if (memcmp (data + FP_OFFSET, device->fingerprint, sizeof (device->fingerprint)) == 0) {
|
if (memcmp (data + FP_OFFSET, device->fingerprint, sizeof (device->fingerprint)) == 0) {
|
||||||
dc_buffer_free (buffer);
|
dc_buffer_free (buffer);
|
||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
|
|||||||
@ -36,7 +36,7 @@ dc_status_t
|
|||||||
atomics_cobalt_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
atomics_cobalt_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
atomics_cobalt_parser_create (dc_parser_t **parser, dc_context_t *context);
|
atomics_cobalt_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,11 +40,10 @@ typedef struct atomics_cobalt_parser_t atomics_cobalt_parser_t;
|
|||||||
struct atomics_cobalt_parser_t {
|
struct atomics_cobalt_parser_t {
|
||||||
dc_parser_t base;
|
dc_parser_t base;
|
||||||
// Depth calibration.
|
// Depth calibration.
|
||||||
double atmospheric;
|
|
||||||
double hydrostatic;
|
double hydrostatic;
|
||||||
};
|
};
|
||||||
|
|
||||||
static dc_status_t atomics_cobalt_parser_set_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_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||||
static dc_status_t atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
static dc_status_t atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||||
static dc_status_t atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
static dc_status_t atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||||
@ -52,7 +51,9 @@ static dc_status_t atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract,
|
|||||||
static const dc_parser_vtable_t atomics_cobalt_parser_vtable = {
|
static const dc_parser_vtable_t atomics_cobalt_parser_vtable = {
|
||||||
sizeof(atomics_cobalt_parser_t),
|
sizeof(atomics_cobalt_parser_t),
|
||||||
DC_FAMILY_ATOMICS_COBALT,
|
DC_FAMILY_ATOMICS_COBALT,
|
||||||
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_datetime, /* datetime */
|
||||||
atomics_cobalt_parser_get_field, /* fields */
|
atomics_cobalt_parser_get_field, /* fields */
|
||||||
atomics_cobalt_parser_samples_foreach, /* samples_foreach */
|
atomics_cobalt_parser_samples_foreach, /* samples_foreach */
|
||||||
@ -61,7 +62,7 @@ static const dc_parser_vtable_t atomics_cobalt_parser_vtable = {
|
|||||||
|
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context)
|
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;
|
atomics_cobalt_parser_t *parser = NULL;
|
||||||
|
|
||||||
@ -69,15 +70,14 @@ atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context)
|
|||||||
return DC_STATUS_INVALIDARGS;
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
// Allocate memory.
|
// Allocate memory.
|
||||||
parser = (atomics_cobalt_parser_t *) dc_parser_allocate (context, &atomics_cobalt_parser_vtable);
|
parser = (atomics_cobalt_parser_t *) dc_parser_allocate (context, &atomics_cobalt_parser_vtable, data, size);
|
||||||
if (parser == NULL) {
|
if (parser == NULL) {
|
||||||
ERROR (context, "Failed to allocate memory.");
|
ERROR (context, "Failed to allocate memory.");
|
||||||
return DC_STATUS_NOMEMORY;
|
return DC_STATUS_NOMEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the default values.
|
// Set the default values.
|
||||||
parser->atmospheric = 0.0;
|
parser->hydrostatic = DEF_DENSITY_SALT * GRAVITY;
|
||||||
parser->hydrostatic = 1025.0 * GRAVITY;
|
|
||||||
|
|
||||||
*out = (dc_parser_t*) parser;
|
*out = (dc_parser_t*) parser;
|
||||||
|
|
||||||
@ -86,22 +86,11 @@ atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context)
|
|||||||
|
|
||||||
|
|
||||||
static dc_status_t
|
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;
|
||||||
}
|
|
||||||
|
|
||||||
|
parser->hydrostatic = density * GRAVITY;
|
||||||
dc_status_t
|
|
||||||
atomics_cobalt_parser_set_calibration (dc_parser_t *abstract, double atmospheric, double hydrostatic)
|
|
||||||
{
|
|
||||||
atomics_cobalt_parser_t *parser = (atomics_cobalt_parser_t*) abstract;
|
|
||||||
|
|
||||||
if (!ISINSTANCE (abstract))
|
|
||||||
return DC_STATUS_INVALIDARGS;
|
|
||||||
|
|
||||||
parser->atmospheric = atmospheric;
|
|
||||||
parser->hydrostatic = hydrostatic;
|
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -142,11 +131,7 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
|||||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||||
dc_tank_t *tank = (dc_tank_t *) value;
|
dc_tank_t *tank = (dc_tank_t *) value;
|
||||||
|
|
||||||
double atmospheric = 0.0;
|
unsigned int atmospheric = array_uint16_le (p + 0x26);
|
||||||
if (parser->atmospheric)
|
|
||||||
atmospheric = parser->atmospheric;
|
|
||||||
else
|
|
||||||
atmospheric = array_uint16_le (p + 0x26) * BAR / 1000.0;
|
|
||||||
|
|
||||||
unsigned int workpressure = 0;
|
unsigned int workpressure = 0;
|
||||||
|
|
||||||
@ -156,13 +141,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;
|
*((unsigned int *) value) = array_uint16_le (p + 0x58) * 60;
|
||||||
break;
|
break;
|
||||||
case DC_FIELD_MAXDEPTH:
|
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;
|
break;
|
||||||
case DC_FIELD_GASMIX_COUNT:
|
case DC_FIELD_GASMIX_COUNT:
|
||||||
case DC_FIELD_TANK_COUNT:
|
case DC_FIELD_TANK_COUNT:
|
||||||
*((unsigned int *) value) = p[0x2a];
|
*((unsigned int *) value) = p[0x2a];
|
||||||
break;
|
break;
|
||||||
case DC_FIELD_GASMIX:
|
case DC_FIELD_GASMIX:
|
||||||
|
gasmix->usage = DC_USAGE_NONE;
|
||||||
gasmix->helium = p[SZ_HEADER + SZ_GASMIX * flags + 5] / 100.0;
|
gasmix->helium = p[SZ_HEADER + SZ_GASMIX * flags + 5] / 100.0;
|
||||||
gasmix->oxygen = p[SZ_HEADER + SZ_GASMIX * flags + 4] / 100.0;
|
gasmix->oxygen = p[SZ_HEADER + SZ_GASMIX * flags + 4] / 100.0;
|
||||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||||
@ -194,6 +180,7 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
|||||||
tank->gasmix = flags;
|
tank->gasmix = flags;
|
||||||
tank->beginpressure = array_uint16_le(p + 6) * PSI / BAR;
|
tank->beginpressure = array_uint16_le(p + 6) * PSI / BAR;
|
||||||
tank->endpressure = array_uint16_le(p + 14) * PSI / BAR;
|
tank->endpressure = array_uint16_le(p + 14) * PSI / BAR;
|
||||||
|
tank->usage = DC_USAGE_NONE;
|
||||||
break;
|
break;
|
||||||
case DC_FIELD_DIVEMODE:
|
case DC_FIELD_DIVEMODE:
|
||||||
switch(p[0x24]) {
|
switch(p[0x24]) {
|
||||||
@ -208,6 +195,9 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
|||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DC_FIELD_ATMOSPHERIC:
|
||||||
|
*((double *) value) = atmospheric / 1000.0;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return DC_STATUS_UNSUPPORTED;
|
return DC_STATUS_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
@ -239,11 +229,7 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
|||||||
if (size < header + SZ_SEGMENT * nsegments)
|
if (size < header + SZ_SEGMENT * nsegments)
|
||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
|
||||||
double atmospheric = 0.0;
|
unsigned int atmospheric = array_uint16_le (data + 0x26);
|
||||||
if (parser->atmospheric)
|
|
||||||
atmospheric = parser->atmospheric;
|
|
||||||
else
|
|
||||||
atmospheric = array_uint16_le (data + 0x26) * BAR / 1000.0;
|
|
||||||
|
|
||||||
// Previous gas mix - initialize with impossible value
|
// Previous gas mix - initialize with impossible value
|
||||||
unsigned int gasmix_previous = 0xFFFFFFFF;
|
unsigned int gasmix_previous = 0xFFFFFFFF;
|
||||||
@ -269,19 +255,19 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
|||||||
|
|
||||||
// Time (seconds).
|
// Time (seconds).
|
||||||
time += interval;
|
time += interval;
|
||||||
sample.time = time;
|
sample.time = time * 1000;
|
||||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||||
|
|
||||||
// Depth (1/1000 bar).
|
// Depth (1/1000 bar).
|
||||||
unsigned int depth = array_uint16_le (data + offset + 0);
|
unsigned int depth = array_uint16_le (data + offset + 0);
|
||||||
sample.depth = (depth * BAR / 1000.0 - atmospheric) / parser->hydrostatic;
|
sample.depth = (signed int)(depth - atmospheric) * (BAR / 1000.0) / parser->hydrostatic;
|
||||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||||
|
|
||||||
// Pressure (1 psi).
|
// Pressure (1 psi).
|
||||||
unsigned int pressure = array_uint16_le (data + offset + 2);
|
unsigned int pressure = array_uint16_le (data + offset + 2);
|
||||||
sample.pressure.tank = tank;
|
sample.pressure.tank = tank;
|
||||||
sample.pressure.value = pressure * PSI / BAR;
|
sample.pressure.value = pressure * PSI / BAR;
|
||||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||||
|
|
||||||
// Current gas mix
|
// Current gas mix
|
||||||
unsigned int gasmix = data[offset + 4];
|
unsigned int gasmix = data[offset + 4];
|
||||||
@ -297,14 +283,14 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
|||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
sample.gasmix = idx;
|
sample.gasmix = idx;
|
||||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||||
gasmix_previous = gasmix;
|
gasmix_previous = gasmix;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temperature (1 °F).
|
// Temperature (1 °F).
|
||||||
unsigned int temperature = data[offset + 8];
|
unsigned int temperature = data[offset + 8];
|
||||||
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
||||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||||
|
|
||||||
// violation status
|
// violation status
|
||||||
sample.event.type = 0;
|
sample.event.type = 0;
|
||||||
@ -314,15 +300,15 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
|||||||
unsigned int violation = data[offset + 11];
|
unsigned int violation = data[offset + 11];
|
||||||
if (violation & 0x01) {
|
if (violation & 0x01) {
|
||||||
sample.event.type = SAMPLE_EVENT_ASCENT;
|
sample.event.type = SAMPLE_EVENT_ASCENT;
|
||||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||||
}
|
}
|
||||||
if (violation & 0x04) {
|
if (violation & 0x04) {
|
||||||
sample.event.type = SAMPLE_EVENT_CEILING;
|
sample.event.type = SAMPLE_EVENT_CEILING;
|
||||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||||
}
|
}
|
||||||
if (violation & 0x08) {
|
if (violation & 0x08) {
|
||||||
sample.event.type = SAMPLE_EVENT_PO2;
|
sample.event.type = SAMPLE_EVENT_PO2;
|
||||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NDL & deco
|
// NDL & deco
|
||||||
@ -337,7 +323,8 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
|||||||
sample.deco.type = DC_DECO_NDL;
|
sample.deco.type = DC_DECO_NDL;
|
||||||
sample.deco.time = ndl;
|
sample.deco.time = ndl;
|
||||||
sample.deco.depth = 0.0;
|
sample.deco.depth = 0.0;
|
||||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
sample.deco.tts = 0;
|
||||||
|
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||||
|
|
||||||
offset += SZ_SEGMENT;
|
offset += SZ_SEGMENT;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h> // malloc, free
|
#include <stdlib.h> // malloc, free
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
|
|
||||||
@ -52,7 +51,6 @@
|
|||||||
#include "context-private.h"
|
#include "context-private.h"
|
||||||
#include "iostream-private.h"
|
#include "iostream-private.h"
|
||||||
#include "iterator-private.h"
|
#include "iterator-private.h"
|
||||||
#include "descriptor-private.h"
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -231,7 +229,7 @@ dc_bluetooth_addr2str(dc_bluetooth_address_t address, char *str, size_t size)
|
|||||||
if (str == NULL || size < DC_BLUETOOTH_SIZE)
|
if (str == NULL || size < DC_BLUETOOTH_SIZE)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
int n = 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 >> 40) & 0xFF),
|
||||||
(unsigned char)((address >> 32) & 0xFF),
|
(unsigned char)((address >> 32) & 0xFF),
|
||||||
(unsigned char)((address >> 24) & 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",
|
INFO (abstract->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s",
|
||||||
address, name ? name : "");
|
address, name ? name : "");
|
||||||
|
|
||||||
if (!dc_descriptor_filter (iterator->descriptor, DC_TRANSPORT_BLUETOOTH, name, NULL)) {
|
if (!dc_descriptor_filter (iterator->descriptor, DC_TRANSPORT_BLUETOOTH, name)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
180
src/checksum.c
180
src/checksum.c
@ -68,8 +68,13 @@ checksum_xor_uint8 (const unsigned char data[], unsigned int size, unsigned char
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Polynomial: 0x1021
|
||||||
|
* RefIn: False
|
||||||
|
* RefOut: False
|
||||||
|
*/
|
||||||
unsigned short
|
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[] = {
|
static const unsigned short crc_ccitt_table[] = {
|
||||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
|
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)
|
for (unsigned int i = 0; i < size; ++i)
|
||||||
crc = (crc << 8) ^ crc_ccitt_table[(crc >> 8) ^ data[i]];
|
crc = (crc << 8) ^ crc_ccitt_table[(crc >> 8) ^ data[i]];
|
||||||
|
|
||||||
return crc;
|
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
|
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[] = {
|
static const unsigned int crc_table[] = {
|
||||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||||
@ -158,8 +322,16 @@ checksum_crc32 (const unsigned char data[], unsigned int size)
|
|||||||
return crc ^ 0xffffffff;
|
return crc ^ 0xffffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Polynomial: 0x04C11DB7
|
||||||
|
* Init: 0xffffffff
|
||||||
|
* XorOut: 0xffffffff
|
||||||
|
* RefIn: False
|
||||||
|
* RefOut: False
|
||||||
|
*/
|
||||||
unsigned int
|
unsigned int
|
||||||
checksum_crc32b (const unsigned char data[], unsigned int size)
|
checksum_crc32 (const unsigned char data[], unsigned int size)
|
||||||
{
|
{
|
||||||
static const unsigned int crc_table[] = {
|
static const unsigned int crc_table[] = {
|
||||||
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
|
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);
|
checksum_xor_uint8 (const unsigned char data[], unsigned int size, unsigned char init);
|
||||||
|
|
||||||
unsigned short
|
unsigned short
|
||||||
checksum_crc16_ccitt (const unsigned char data[], unsigned int size, unsigned short init);
|
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
|
unsigned int
|
||||||
checksum_crc32 (const unsigned char data[], unsigned int size);
|
checksum_crc32 (const unsigned char data[], unsigned int size);
|
||||||
|
|
||||||
unsigned int
|
|
||||||
checksum_crc32b (const unsigned char data[], unsigned int size);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|||||||
@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
#define ISINSTANCE(device) dc_device_isinstance((device), &citizen_aqualand_device_vtable)
|
#define ISINSTANCE(device) dc_device_isinstance((device), &citizen_aqualand_device_vtable)
|
||||||
|
|
||||||
|
#define SZ_HEADER 32
|
||||||
|
|
||||||
typedef struct citizen_aqualand_device_t {
|
typedef struct citizen_aqualand_device_t {
|
||||||
dc_device_t base;
|
dc_device_t base;
|
||||||
dc_iostream_t *iostream;
|
dc_iostream_t *iostream;
|
||||||
@ -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 char *data = dc_buffer_get_data (buffer);
|
||||||
unsigned int size = dc_buffer_get_size (buffer);
|
unsigned int size = dc_buffer_get_size (buffer);
|
||||||
|
|
||||||
|
if (size < SZ_HEADER) {
|
||||||
|
ERROR (abstract->context, "Dive header is too small (%u).", size);
|
||||||
|
dc_buffer_free (buffer);
|
||||||
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
if (callback && memcmp (data + 0x05, device->fingerprint, sizeof (device->fingerprint)) != 0) {
|
if (callback && memcmp (data + 0x05, device->fingerprint, sizeof (device->fingerprint)) != 0) {
|
||||||
callback (data, size, data + 0x05, sizeof (device->fingerprint), userdata);
|
callback (data, size, data + 0x05, sizeof (device->fingerprint), userdata);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,7 +35,7 @@ dc_status_t
|
|||||||
citizen_aqualand_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
citizen_aqualand_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
citizen_aqualand_parser_create (dc_parser_t **parser, dc_context_t *context);
|
citizen_aqualand_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,7 +36,6 @@ typedef struct citizen_aqualand_parser_t {
|
|||||||
dc_parser_t base;
|
dc_parser_t base;
|
||||||
} citizen_aqualand_parser_t;
|
} citizen_aqualand_parser_t;
|
||||||
|
|
||||||
static dc_status_t citizen_aqualand_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
|
||||||
static dc_status_t citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
static dc_status_t citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||||
static dc_status_t citizen_aqualand_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
static dc_status_t citizen_aqualand_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||||
static dc_status_t citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
static dc_status_t citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||||
@ -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 = {
|
static const dc_parser_vtable_t citizen_aqualand_parser_vtable = {
|
||||||
sizeof(citizen_aqualand_parser_t),
|
sizeof(citizen_aqualand_parser_t),
|
||||||
DC_FAMILY_CITIZEN_AQUALAND,
|
DC_FAMILY_CITIZEN_AQUALAND,
|
||||||
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_datetime, /* datetime */
|
||||||
citizen_aqualand_parser_get_field, /* fields */
|
citizen_aqualand_parser_get_field, /* fields */
|
||||||
citizen_aqualand_parser_samples_foreach, /* samples_foreach */
|
citizen_aqualand_parser_samples_foreach, /* samples_foreach */
|
||||||
@ -53,7 +54,7 @@ static const dc_parser_vtable_t citizen_aqualand_parser_vtable = {
|
|||||||
|
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context)
|
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;
|
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;
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
// Allocate memory.
|
// 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) {
|
if (parser == NULL) {
|
||||||
ERROR (context, "Failed to allocate memory.");
|
ERROR (context, "Failed to allocate memory.");
|
||||||
return DC_STATUS_NOMEMORY;
|
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
|
static dc_status_t
|
||||||
citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||||
{
|
{
|
||||||
@ -238,15 +232,15 @@ citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
|||||||
|
|
||||||
// Time
|
// Time
|
||||||
time += interval;
|
time += interval;
|
||||||
sample.time = time;
|
sample.time = time * 1000;
|
||||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||||
|
|
||||||
// Depth
|
// Depth
|
||||||
if (metric)
|
if (metric)
|
||||||
sample.depth = depth / 10.0;
|
sample.depth = depth / 10.0;
|
||||||
else
|
else
|
||||||
sample.depth = depth * FEET;
|
sample.depth = depth * FEET;
|
||||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||||
|
|
||||||
// Temperature
|
// Temperature
|
||||||
if (time % 300 == 0) {
|
if (time % 300 == 0) {
|
||||||
@ -257,7 +251,7 @@ citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
|||||||
sample.temperature = temperature / 10.0;
|
sample.temperature = temperature / 10.0;
|
||||||
else
|
else
|
||||||
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
||||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,8 +30,6 @@
|
|||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include "rbstream.h"
|
#include "rbstream.h"
|
||||||
|
|
||||||
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
|
|
||||||
|
|
||||||
#define MAXRETRIES 2
|
#define MAXRETRIES 2
|
||||||
|
|
||||||
#define COCHRAN_MODEL_COMMANDER_TM 0
|
#define COCHRAN_MODEL_COMMANDER_TM 0
|
||||||
@ -605,7 +603,7 @@ cochran_commander_profile_size(cochran_commander_device_t *device, cochran_data_
|
|||||||
// Corrupt dive, guess the end address
|
// Corrupt dive, guess the end address
|
||||||
sample_end_address = cochran_commander_guess_sample_end_address(device, data, dive_num);
|
sample_end_address = cochran_commander_guess_sample_end_address(device, data, dive_num);
|
||||||
|
|
||||||
return ringbuffer_distance(sample_start_address, sample_end_address, 0, device->layout->rb_profile_begin, device->layout->rb_profile_end);
|
return ringbuffer_distance(sample_start_address, sample_end_address, DC_RINGBUFFER_EMPTY, device->layout->rb_profile_begin, device->layout->rb_profile_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -967,7 +965,7 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
|
|||||||
last_start_address = base + array_uint32_le(data.config + layout->cf_last_log );
|
last_start_address = base + array_uint32_le(data.config + layout->cf_last_log );
|
||||||
|
|
||||||
// Create the ringbuffer stream.
|
// Create the ringbuffer stream.
|
||||||
status = dc_rbstream_new (&rbstream, abstract, 1, layout->rbstream_size, layout->rb_profile_begin, layout->rb_profile_end, last_start_address);
|
status = dc_rbstream_new (&rbstream, abstract, 1, layout->rbstream_size, layout->rb_profile_begin, layout->rb_profile_end, last_start_address, DC_RBSTREAM_BACKWARD);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||||
goto error;
|
goto error;
|
||||||
|
|||||||
@ -35,7 +35,7 @@ dc_status_t
|
|||||||
cochran_commander_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
cochran_commander_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
cochran_commander_parser_create (dc_parser_t **parser, dc_context_t *context, 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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,8 +29,6 @@
|
|||||||
#include "parser-private.h"
|
#include "parser-private.h"
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
|
|
||||||
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
|
|
||||||
|
|
||||||
#define COCHRAN_MODEL_COMMANDER_TM 0
|
#define COCHRAN_MODEL_COMMANDER_TM 0
|
||||||
#define COCHRAN_MODEL_COMMANDER_PRE21000 1
|
#define COCHRAN_MODEL_COMMANDER_PRE21000 1
|
||||||
#define COCHRAN_MODEL_COMMANDER_AIR_NITROX 2
|
#define COCHRAN_MODEL_COMMANDER_AIR_NITROX 2
|
||||||
@ -101,7 +99,6 @@ typedef struct cochran_commander_parser_t {
|
|||||||
unsigned int nevents;
|
unsigned int nevents;
|
||||||
} cochran_commander_parser_t ;
|
} cochran_commander_parser_t ;
|
||||||
|
|
||||||
static dc_status_t cochran_commander_parser_set_data (dc_parser_t *parser, const unsigned char *data, unsigned int size);
|
|
||||||
static dc_status_t cochran_commander_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime);
|
static dc_status_t cochran_commander_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime);
|
||||||
static dc_status_t cochran_commander_parser_get_field (dc_parser_t *parser, dc_field_type_t type, unsigned int flags, void *value);
|
static dc_status_t cochran_commander_parser_get_field (dc_parser_t *parser, dc_field_type_t type, unsigned int flags, void *value);
|
||||||
static dc_status_t cochran_commander_parser_samples_foreach (dc_parser_t *parser, dc_sample_callback_t callback, void *userdata);
|
static dc_status_t cochran_commander_parser_samples_foreach (dc_parser_t *parser, dc_sample_callback_t callback, void *userdata);
|
||||||
@ -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 = {
|
static const dc_parser_vtable_t cochran_commander_parser_vtable = {
|
||||||
sizeof(cochran_commander_parser_t),
|
sizeof(cochran_commander_parser_t),
|
||||||
DC_FAMILY_COCHRAN_COMMANDER,
|
DC_FAMILY_COCHRAN_COMMANDER,
|
||||||
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_datetime, /* datetime */
|
||||||
cochran_commander_parser_get_field, /* fields */
|
cochran_commander_parser_get_field, /* fields */
|
||||||
cochran_commander_parser_samples_foreach, /* samples_foreach */
|
cochran_commander_parser_samples_foreach, /* samples_foreach */
|
||||||
@ -314,7 +313,7 @@ cochran_commander_handle_event (cochran_commander_parser_t *parser, unsigned cha
|
|||||||
sample.event.time = 0;
|
sample.event.time = 0;
|
||||||
sample.event.value = 0;
|
sample.event.value = 0;
|
||||||
sample.event.flags = event->flag;
|
sample.event.flags = event->flag;
|
||||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,7 +350,7 @@ cochran_commander_backparse(cochran_commander_parser_t *parser, const unsigned c
|
|||||||
|
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
cochran_commander_parser_create (dc_parser_t **out, dc_context_t *context, 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;
|
cochran_commander_parser_t *parser = NULL;
|
||||||
dc_status_t status = DC_STATUS_SUCCESS;
|
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;
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
// Allocate memory.
|
// 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) {
|
if (parser == NULL) {
|
||||||
ERROR (context, "Failed to allocate memory.");
|
ERROR (context, "Failed to allocate memory.");
|
||||||
return DC_STATUS_NOMEMORY;
|
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
|
static dc_status_t
|
||||||
cochran_commander_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
cochran_commander_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||||
{
|
{
|
||||||
@ -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
|
// Gas percentages are decimal and encoded as
|
||||||
// highbyte = integer portion
|
// highbyte = integer portion
|
||||||
// lowbyte = decimal portion, divide by 256 to get decimal value
|
// lowbyte = decimal portion, divide by 256 to get decimal value
|
||||||
|
gasmix->usage = DC_USAGE_NONE;
|
||||||
gasmix->oxygen = array_uint16_le (data + layout->oxygen + 2 * flags) / 256.0 / 100;
|
gasmix->oxygen = array_uint16_le (data + layout->oxygen + 2 * flags) / 256.0 / 100;
|
||||||
if (layout->helium == UNSUPPORTED) {
|
if (layout->helium == UNSUPPORTED) {
|
||||||
gasmix->helium = 0;
|
gasmix->helium = 0;
|
||||||
@ -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 temp = samples[0]; // Half degrees F
|
||||||
unsigned int depth = samples[1]; // Half feet
|
unsigned int depth = samples[1]; // Half feet
|
||||||
|
|
||||||
last_sample_time = sample.time = time;
|
last_sample_time = sample.time = time * 1000;
|
||||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||||
|
|
||||||
sample.depth = (depth / 2.0) * FEET;
|
sample.depth = (depth / 2.0) * FEET;
|
||||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||||
|
|
||||||
sample.temperature = (temp / 2.0 - 32.0) / 1.8;
|
sample.temperature = (temp / 2.0 - 32.0) / 1.8;
|
||||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||||
|
|
||||||
sample.gasmix = 0;
|
sample.gasmix = 0;
|
||||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||||
|
|
||||||
while (offset < size) {
|
while (offset < size) {
|
||||||
const unsigned char *s = samples + offset;
|
const unsigned char *s = samples + offset;
|
||||||
|
|
||||||
sample.time = time;
|
sample.time = time * 1000;
|
||||||
if (last_sample_time != sample.time) {
|
if (last_sample_time != sample.time) {
|
||||||
// We haven't issued this time yet.
|
// We haven't issued this time yet.
|
||||||
last_sample_time = sample.time;
|
last_sample_time = sample.time;
|
||||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*s & 0x80) {
|
if (*s & 0x80) {
|
||||||
@ -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.type = DC_DECO_DECOSTOP;
|
||||||
sample.deco.time = 60; // We don't know the duration
|
sample.deco.time = 60; // We don't know the duration
|
||||||
sample.deco.depth = deco_ceiling * FEET;
|
sample.deco.depth = deco_ceiling * FEET;
|
||||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
sample.deco.tts = 0;
|
||||||
|
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||||
break;
|
break;
|
||||||
case 0xAD: // Increment ceiling (shallower)
|
case 0xAD: // Increment ceiling (shallower)
|
||||||
deco_ceiling -= 10; // feet
|
deco_ceiling -= 10; // feet
|
||||||
@ -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.type = DC_DECO_DECOSTOP;
|
||||||
sample.deco.depth = deco_ceiling * FEET;
|
sample.deco.depth = deco_ceiling * FEET;
|
||||||
sample.deco.time = 60; // We don't know the duration
|
sample.deco.time = 60; // We don't know the duration
|
||||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
sample.deco.tts = 0;
|
||||||
|
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cochran_commander_handle_event(parser, s[0], callback, userdata);
|
cochran_commander_handle_event(parser, s[0], callback, userdata);
|
||||||
@ -635,7 +630,7 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
|||||||
else
|
else
|
||||||
temp += (*s & 0x0f);
|
temp += (*s & 0x0f);
|
||||||
sample.temperature = (temp / 2.0 - 32.0) / 1.8;
|
sample.temperature = (temp / 2.0 - 32.0) / 1.8;
|
||||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
offset++;
|
offset++;
|
||||||
@ -649,7 +644,7 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
|||||||
depth += s[0] & 0x3f;
|
depth += s[0] & 0x3f;
|
||||||
|
|
||||||
sample.depth = (depth / 2.0) * FEET;
|
sample.depth = (depth / 2.0) * FEET;
|
||||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||||
|
|
||||||
offset++;
|
offset++;
|
||||||
time += sample_interval;
|
time += sample_interval;
|
||||||
@ -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;
|
start_depth = array_uint16_le (data + layout->start_depth) / 256.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_sample_time = sample.time = time;
|
last_sample_time = sample.time = time * 1000;
|
||||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||||
|
|
||||||
sample.depth = start_depth * FEET;
|
sample.depth = start_depth * FEET;
|
||||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||||
|
|
||||||
sample.temperature = (data[layout->start_temp] - 32.0) / 1.8;
|
sample.temperature = (data[layout->start_temp] - 32.0) / 1.8;
|
||||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||||
|
|
||||||
sample.gasmix = 0;
|
sample.gasmix = 0;
|
||||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||||
unsigned int last_gasmix = sample.gasmix;
|
unsigned int last_gasmix = sample.gasmix;
|
||||||
|
|
||||||
while (offset < size) {
|
while (offset < size) {
|
||||||
const unsigned char *s = samples + offset;
|
const unsigned char *s = samples + offset;
|
||||||
|
|
||||||
sample.time = time;
|
sample.time = time * 1000;
|
||||||
if (last_sample_time != sample.time) {
|
if (last_sample_time != sample.time) {
|
||||||
// We haven't issued this time yet.
|
// We haven't issued this time yet.
|
||||||
last_sample_time = sample.time;
|
last_sample_time = sample.time;
|
||||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If corrupt_dive end before offset
|
// If corrupt_dive end before offset
|
||||||
@ -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.type = DC_DECO_DECOSTOP;
|
||||||
sample.deco.time = (array_uint16_le(s + 3) + 1) * 60;
|
sample.deco.time = (array_uint16_le(s + 3) + 1) * 60;
|
||||||
sample.deco.depth = deco_ceiling * FEET;
|
sample.deco.depth = deco_ceiling * FEET;
|
||||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
sample.deco.tts = 0;
|
||||||
|
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||||
break;
|
break;
|
||||||
case 0xAD: // Increment ceiling (shallower)
|
case 0xAD: // Increment ceiling (shallower)
|
||||||
deco_ceiling -= 10; // feet
|
deco_ceiling -= 10; // feet
|
||||||
@ -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.type = DC_DECO_DECOSTOP;
|
||||||
sample.deco.depth = deco_ceiling * FEET;
|
sample.deco.depth = deco_ceiling * FEET;
|
||||||
sample.deco.time = (array_uint16_le(s + 3) + 1) * 60;
|
sample.deco.time = (array_uint16_le(s + 3) + 1) * 60;
|
||||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
sample.deco.tts = 0;
|
||||||
|
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||||
break;
|
break;
|
||||||
case 0xC0: // Switched to FO2 21% mode (surface)
|
case 0xC0: // Switched to FO2 21% mode (surface)
|
||||||
// Event seen upon surfacing
|
// Event seen upon surfacing
|
||||||
@ -790,14 +787,14 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
|||||||
case 0xEF: // Switched to gas blend 2
|
case 0xEF: // Switched to gas blend 2
|
||||||
if (last_gasmix != 1) {
|
if (last_gasmix != 1) {
|
||||||
sample.gasmix = 1;
|
sample.gasmix = 1;
|
||||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||||
last_gasmix = sample.gasmix;
|
last_gasmix = sample.gasmix;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xF3: // Switched to gas blend 1
|
case 0xF3: // Switched to gas blend 1
|
||||||
if (last_gasmix != 0) {
|
if (last_gasmix != 0) {
|
||||||
sample.gasmix = 0;
|
sample.gasmix = 0;
|
||||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||||
last_gasmix = sample.gasmix;
|
last_gasmix = sample.gasmix;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -817,7 +814,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
|||||||
depth += (s[0] & 0x3f);
|
depth += (s[0] & 0x3f);
|
||||||
|
|
||||||
sample.depth = (start_depth + depth / 4.0) * FEET;
|
sample.depth = (start_depth + depth / 4.0) * FEET;
|
||||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||||
|
|
||||||
// Ascent rate is logged in the 0th sample, temp in the 1st, repeat.
|
// Ascent rate is logged in the 0th sample, temp in the 1st, repeat.
|
||||||
if (time % 2 == 0) {
|
if (time % 2 == 0) {
|
||||||
@ -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;
|
double temperature = s[1] / 2.0 + 20.0;
|
||||||
sample.temperature = (temperature - 32.0) / 1.8;
|
sample.temperature = (temperature - 32.0) / 1.8;
|
||||||
|
|
||||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cochran EMC models store NDL and deco stop time
|
// Cochran EMC models store NDL and deco stop time
|
||||||
@ -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.type = DC_DECO_NDL;
|
||||||
sample.deco.time = deco_time * 60;
|
sample.deco.time = deco_time * 60;
|
||||||
sample.deco.depth = 0;
|
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;
|
break;
|
||||||
case 23:
|
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.type = DC_DECO_DECOSTOP;
|
||||||
sample.deco.depth = deco_ceiling * FEET;
|
sample.deco.depth = deco_ceiling * FEET;
|
||||||
sample.deco.time = deco_time * 60;
|
sample.deco.time = deco_time * 60;
|
||||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
sample.deco.tts = 0;
|
||||||
|
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
#include <libdivecomputer/context.h>
|
#include <libdivecomputer/context.h>
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
@ -40,12 +42,6 @@ extern "C" {
|
|||||||
#define FUNCTION __FUNCTION__
|
#define FUNCTION __FUNCTION__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
|
||||||
#define ATTR_FORMAT_PRINTF(a,b) __attribute__((format(printf, a, b)))
|
|
||||||
#else
|
|
||||||
#define ATTR_FORMAT_PRINTF(a,b)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ENABLE_LOGGING
|
#ifdef ENABLE_LOGGING
|
||||||
#define HEXDUMP(context, loglevel, prefix, data, size) dc_context_hexdump (context, loglevel, __FILE__, __LINE__, FUNCTION, prefix, data, size)
|
#define HEXDUMP(context, loglevel, prefix, data, size) dc_context_hexdump (context, loglevel, __FILE__, __LINE__, FUNCTION, prefix, data, size)
|
||||||
#define SYSERROR(context, errcode) dc_context_syserror (context, DC_LOGLEVEL_ERROR, __FILE__, __LINE__, FUNCTION, errcode)
|
#define SYSERROR(context, errcode) dc_context_syserror (context, DC_LOGLEVEL_ERROR, __FILE__, __LINE__, FUNCTION, errcode)
|
||||||
@ -63,7 +59,7 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
dc_context_log (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, const char *format, ...) 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_status_t
|
||||||
dc_context_syserror (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, int errcode);
|
dc_context_syserror (dc_context_t *context, dc_loglevel_t loglevel, const char *file, unsigned int line, const char *function, int errcode);
|
||||||
|
|||||||
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
@ -36,6 +35,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "context-private.h"
|
#include "context-private.h"
|
||||||
|
#include "platform.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
|
||||||
struct dc_context_t {
|
struct dc_context_t {
|
||||||
@ -49,55 +49,6 @@ struct dc_context_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef ENABLE_LOGGING
|
#ifdef ENABLE_LOGGING
|
||||||
/*
|
|
||||||
* A wrapper for the vsnprintf function, which will always null terminate the
|
|
||||||
* string and returns a negative value if the destination buffer is too small.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
l_vsnprintf (char *str, size_t size, const char *format, va_list ap)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
|
|
||||||
if (size == 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
/*
|
|
||||||
* The non-standard vsnprintf implementation provided by MSVC doesn't null
|
|
||||||
* terminate the string and returns a negative value if the destination
|
|
||||||
* buffer is too small.
|
|
||||||
*/
|
|
||||||
n = _vsnprintf (str, size - 1, format, ap);
|
|
||||||
if (n == size - 1 || n < 0)
|
|
||||||
str[size - 1] = 0;
|
|
||||||
#else
|
|
||||||
/*
|
|
||||||
* The C99 vsnprintf function will always null terminate the string. If the
|
|
||||||
* destination buffer is too small, the return value is the number of
|
|
||||||
* characters that would have been written if the buffer had been large
|
|
||||||
* enough.
|
|
||||||
*/
|
|
||||||
n = vsnprintf (str, size, format, ap);
|
|
||||||
if (n >= 0 && (size_t) n >= size)
|
|
||||||
n = -1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
l_snprintf (char *str, size_t size, const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
va_start (ap, format);
|
|
||||||
n = l_vsnprintf (str, size, format, ap);
|
|
||||||
va_end (ap);
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
l_hexdump (char *str, size_t size, const unsigned char data[], size_t n)
|
l_hexdump (char *str, size_t size, const unsigned char data[], size_t n)
|
||||||
{
|
{
|
||||||
@ -244,7 +195,7 @@ dc_context_log (dc_context_t *context, dc_loglevel_t loglevel, const char *file,
|
|||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
|
|
||||||
va_start (ap, format);
|
va_start (ap, format);
|
||||||
l_vsnprintf (context->msg, sizeof (context->msg), format, ap);
|
dc_platform_vsnprintf (context->msg, sizeof (context->msg), format, ap);
|
||||||
va_end (ap);
|
va_end (ap);
|
||||||
|
|
||||||
context->logfunc (context, loglevel, file, line, function, context->msg, context->userdata);
|
context->logfunc (context, loglevel, file, line, function, context->msg, context->userdata);
|
||||||
@ -310,7 +261,7 @@ dc_context_hexdump (dc_context_t *context, dc_loglevel_t loglevel, const char *f
|
|||||||
if (context->logfunc == NULL)
|
if (context->logfunc == NULL)
|
||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
|
|
||||||
n = 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) {
|
if (n >= 0) {
|
||||||
n = l_hexdump (context->msg + n, sizeof (context->msg) - n, data, size);
|
n = l_hexdump (context->msg + n, sizeof (context->msg) - n, data, size);
|
||||||
|
|||||||
@ -38,6 +38,8 @@
|
|||||||
#define SZ_PACKET 0x80
|
#define SZ_PACKET 0x80
|
||||||
#define SZ_PAGE (SZ_PACKET / 4)
|
#define SZ_PAGE (SZ_PACKET / 4)
|
||||||
|
|
||||||
|
#define SZ_HEADER 32
|
||||||
|
|
||||||
#define IQ700 0x05
|
#define IQ700 0x05
|
||||||
#define EDY 0x08
|
#define EDY 0x08
|
||||||
|
|
||||||
@ -379,7 +381,14 @@ cressi_edy_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
|||||||
return DC_STATUS_NOMEMORY;
|
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);
|
dc_buffer_get_size (buffer), SZ_PACKET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,7 +432,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the number of logbook items.
|
// Get the number of logbook items.
|
||||||
unsigned int count = ringbuffer_distance (first, last, 0, layout->rb_logbook_begin, layout->rb_logbook_end) + 1;
|
unsigned int count = ringbuffer_distance (first, last, DC_RINGBUFFER_EMPTY, layout->rb_logbook_begin, layout->rb_logbook_end) + 1;
|
||||||
|
|
||||||
// Get the profile pointer.
|
// Get the profile pointer.
|
||||||
unsigned int eop = array_uint_le (logbook + layout->config + 2, layout->rb_logbook_size) * SZ_PAGE + layout->rb_profile_begin;
|
unsigned int eop = array_uint_le (logbook + layout->config + 2, layout->rb_logbook_size) * SZ_PAGE + layout->rb_profile_begin;
|
||||||
@ -448,7 +457,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the profile length.
|
// Get the profile length.
|
||||||
unsigned int length = ringbuffer_distance (current, previous, 1, layout->rb_profile_begin, layout->rb_profile_end);
|
unsigned int length = ringbuffer_distance (current, previous, DC_RINGBUFFER_FULL, layout->rb_profile_begin, layout->rb_profile_end);
|
||||||
|
|
||||||
// Check for a ringbuffer overflow.
|
// Check for a ringbuffer overflow.
|
||||||
if (total + length > layout->rb_profile_end - layout->rb_profile_begin) {
|
if (total + length > layout->rb_profile_end - layout->rb_profile_begin) {
|
||||||
@ -472,7 +481,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
|
|||||||
|
|
||||||
// Create the ringbuffer stream.
|
// Create the ringbuffer stream.
|
||||||
dc_rbstream_t *rbstream = NULL;
|
dc_rbstream_t *rbstream = NULL;
|
||||||
rc = dc_rbstream_new (&rbstream, abstract, SZ_PAGE, SZ_PACKET, layout->rb_profile_begin, layout->rb_profile_end, eop);
|
rc = dc_rbstream_new (&rbstream, abstract, SZ_PAGE, SZ_PACKET, layout->rb_profile_begin, layout->rb_profile_end, eop, DC_RBSTREAM_BACKWARD);
|
||||||
if (rc != DC_STATUS_SUCCESS) {
|
if (rc != DC_STATUS_SUCCESS) {
|
||||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||||
return rc;
|
return rc;
|
||||||
@ -501,7 +510,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the profile length.
|
// Get the profile length.
|
||||||
unsigned int length = ringbuffer_distance (current, previous, 1, layout->rb_profile_begin, layout->rb_profile_end);
|
unsigned int length = ringbuffer_distance (current, previous, DC_RINGBUFFER_FULL, layout->rb_profile_begin, layout->rb_profile_end);
|
||||||
|
|
||||||
// Move to the begin of the current dive.
|
// Move to the begin of the current dive.
|
||||||
offset -= length;
|
offset -= length;
|
||||||
@ -515,6 +524,13 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (length < SZ_HEADER) {
|
||||||
|
ERROR (abstract->context, "Dive header is too small (%u).", length);
|
||||||
|
dc_rbstream_free (rbstream);
|
||||||
|
free (buffer);
|
||||||
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char *p = buffer + offset;
|
unsigned char *p = buffer + offset;
|
||||||
|
|
||||||
if (memcmp (p, device->fingerprint, sizeof (device->fingerprint)) == 0)
|
if (memcmp (p, device->fingerprint, sizeof (device->fingerprint)) == 0)
|
||||||
|
|||||||
@ -35,7 +35,7 @@ dc_status_t
|
|||||||
cressi_edy_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
cressi_edy_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
cressi_edy_parser_create (dc_parser_t **parser, dc_context_t *context, 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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,6 +31,8 @@
|
|||||||
#define IQ700 0x05
|
#define IQ700 0x05
|
||||||
#define EDY 0x08
|
#define EDY 0x08
|
||||||
|
|
||||||
|
#define SZ_HEADER 32
|
||||||
|
|
||||||
typedef struct cressi_edy_parser_t cressi_edy_parser_t;
|
typedef struct cressi_edy_parser_t cressi_edy_parser_t;
|
||||||
|
|
||||||
struct cressi_edy_parser_t {
|
struct cressi_edy_parser_t {
|
||||||
@ -38,7 +40,6 @@ struct cressi_edy_parser_t {
|
|||||||
unsigned int model;
|
unsigned int model;
|
||||||
};
|
};
|
||||||
|
|
||||||
static dc_status_t cressi_edy_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
|
||||||
static dc_status_t cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
static dc_status_t cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||||
static dc_status_t cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
static dc_status_t cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||||
static dc_status_t cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
static dc_status_t cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||||
@ -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 = {
|
static const dc_parser_vtable_t cressi_edy_parser_vtable = {
|
||||||
sizeof(cressi_edy_parser_t),
|
sizeof(cressi_edy_parser_t),
|
||||||
DC_FAMILY_CRESSI_EDY,
|
DC_FAMILY_CRESSI_EDY,
|
||||||
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_datetime, /* datetime */
|
||||||
cressi_edy_parser_get_field, /* fields */
|
cressi_edy_parser_get_field, /* fields */
|
||||||
cressi_edy_parser_samples_foreach, /* samples_foreach */
|
cressi_edy_parser_samples_foreach, /* samples_foreach */
|
||||||
@ -70,7 +73,7 @@ cressi_edy_parser_count_gasmixes (const unsigned char *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, 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;
|
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;
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
// Allocate memory.
|
// 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) {
|
if (parser == NULL) {
|
||||||
ERROR (context, "Failed to allocate memory.");
|
ERROR (context, "Failed to allocate memory.");
|
||||||
return DC_STATUS_NOMEMORY;
|
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
|
static dc_status_t
|
||||||
cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||||
{
|
{
|
||||||
if (abstract->size < 32)
|
if (abstract->size < SZ_HEADER)
|
||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
|
||||||
const unsigned char *p = abstract->data;
|
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;
|
cressi_edy_parser_t *parser = (cressi_edy_parser_t *) abstract;
|
||||||
|
|
||||||
if (abstract->size < 32)
|
if (abstract->size < SZ_HEADER)
|
||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
|
||||||
const unsigned char *p = abstract->data;
|
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);
|
*((unsigned int *) value) = cressi_edy_parser_count_gasmixes(p);
|
||||||
break;
|
break;
|
||||||
case DC_FIELD_GASMIX:
|
case DC_FIELD_GASMIX:
|
||||||
|
gasmix->usage = DC_USAGE_NONE;
|
||||||
gasmix->helium = 0.0;
|
gasmix->helium = 0.0;
|
||||||
gasmix->oxygen = bcd2dec (p[0x17 - flags]) / 100.0;
|
gasmix->oxygen = bcd2dec (p[0x17 - flags]) / 100.0;
|
||||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||||
@ -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 ngasmixes = cressi_edy_parser_count_gasmixes(data);
|
||||||
unsigned int gasmix = 0xFFFFFFFF;
|
unsigned int gasmix = 0xFFFFFFFF;
|
||||||
|
|
||||||
unsigned int offset = 32;
|
unsigned int offset = SZ_HEADER;
|
||||||
while (offset + 2 <= size) {
|
while (offset + 2 <= size) {
|
||||||
dc_sample_value_t sample = {0};
|
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 (seconds).
|
||||||
time += interval;
|
time += interval;
|
||||||
sample.time = time;
|
sample.time = time * 1000;
|
||||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||||
|
|
||||||
// Depth (1/10 m).
|
// Depth (1/10 m).
|
||||||
unsigned int depth = bcd2dec (data[offset + 0] & 0x0F) * 100 + bcd2dec (data[offset + 1]);
|
unsigned int depth = bcd2dec (data[offset + 0] & 0x0F) * 100 + bcd2dec (data[offset + 1]);
|
||||||
sample.depth = depth / 10.0;
|
sample.depth = depth / 10.0;
|
||||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||||
|
|
||||||
// Current gasmix
|
// Current gasmix
|
||||||
if (ngasmixes) {
|
if (ngasmixes) {
|
||||||
@ -217,7 +214,7 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
|||||||
}
|
}
|
||||||
if (idx != gasmix) {
|
if (idx != gasmix) {
|
||||||
sample.gasmix = idx;
|
sample.gasmix = idx;
|
||||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||||
gasmix = idx;
|
gasmix = idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -93,7 +93,7 @@ cressi_goa_device_send (cressi_goa_device_t *device, unsigned char cmd, const un
|
|||||||
if (size) {
|
if (size) {
|
||||||
memcpy (packet + 5, data, size);
|
memcpy (packet + 5, data, size);
|
||||||
}
|
}
|
||||||
crc = checksum_crc16_ccitt (packet + 3, size + 2, 0x000);
|
crc = checksum_crc16_ccitt (packet + 3, size + 2, 0x000, 0x0000);
|
||||||
packet[5 + size + 0] = (crc ) & 0xFF; // Low
|
packet[5 + size + 0] = (crc ) & 0xFF; // Low
|
||||||
packet[5 + size + 1] = (crc >> 8) & 0xFF; // High
|
packet[5 + size + 1] = (crc >> 8) & 0xFF; // High
|
||||||
packet[5 + size + 2] = TRAILER;
|
packet[5 + size + 2] = TRAILER;
|
||||||
@ -155,7 +155,7 @@ cressi_goa_device_receive (cressi_goa_device_t *device, unsigned char data[], un
|
|||||||
|
|
||||||
// Verify the checksum of the packet.
|
// Verify the checksum of the packet.
|
||||||
unsigned short crc = array_uint16_le (packet + length + 5);
|
unsigned short crc = array_uint16_le (packet + length + 5);
|
||||||
unsigned short ccrc = checksum_crc16_ccitt (packet + 3, length + 2, 0x0000);
|
unsigned short ccrc = checksum_crc16_ccitt (packet + 3, length + 2, 0x0000, 0x0000);
|
||||||
if (crc != ccrc) {
|
if (crc != ccrc) {
|
||||||
ERROR (abstract->context, "Unexpected answer checksum.");
|
ERROR (abstract->context, "Unexpected answer checksum.");
|
||||||
return DC_STATUS_PROTOCOL;
|
return DC_STATUS_PROTOCOL;
|
||||||
@ -203,7 +203,7 @@ cressi_goa_device_download (cressi_goa_device_t *device, dc_buffer_t *buffer, dc
|
|||||||
|
|
||||||
// Verify the checksum of the packet.
|
// Verify the checksum of the packet.
|
||||||
unsigned short crc = array_uint16_le (packet + sizeof(packet) - 2);
|
unsigned short crc = array_uint16_le (packet + sizeof(packet) - 2);
|
||||||
unsigned short ccrc = checksum_crc16_ccitt (packet + 3, sizeof(packet) - 5, 0x0000);
|
unsigned short ccrc = checksum_crc16_ccitt (packet + 3, sizeof(packet) - 5, 0x0000, 0x0000);
|
||||||
if (crc != ccrc) {
|
if (crc != ccrc) {
|
||||||
ERROR (abstract->context, "Unexpected answer checksum.");
|
ERROR (abstract->context, "Unexpected answer checksum.");
|
||||||
return DC_STATUS_PROTOCOL;
|
return DC_STATUS_PROTOCOL;
|
||||||
|
|||||||
@ -35,7 +35,7 @@ dc_status_t
|
|||||||
cressi_goa_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
cressi_goa_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
cressi_goa_parser_create (dc_parser_t **parser, dc_context_t *context, 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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,12 +28,7 @@
|
|||||||
|
|
||||||
#define ISINSTANCE(parser) dc_device_isinstance((parser), &cressi_goa_parser_vtable)
|
#define ISINSTANCE(parser) dc_device_isinstance((parser), &cressi_goa_parser_vtable)
|
||||||
|
|
||||||
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
|
|
||||||
|
|
||||||
#define SZ_HEADER 23
|
#define SZ_HEADER 23
|
||||||
#define SZ_HEADER_SCUBA 0x61
|
|
||||||
#define SZ_HEADER_FREEDIVE 0x2B
|
|
||||||
#define SZ_HEADER_GAUGE 0x2D
|
|
||||||
|
|
||||||
#define DEPTH 0
|
#define DEPTH 0
|
||||||
#define DEPTH2 1
|
#define DEPTH2 1
|
||||||
@ -45,17 +40,28 @@
|
|||||||
#define FREEDIVE 2
|
#define FREEDIVE 2
|
||||||
#define GAUGE 3
|
#define GAUGE 3
|
||||||
|
|
||||||
|
#define NGASMIXES 2
|
||||||
|
|
||||||
|
#define UNDEFINED 0xFFFFFFFF
|
||||||
|
|
||||||
typedef struct cressi_goa_parser_t cressi_goa_parser_t;
|
typedef struct cressi_goa_parser_t cressi_goa_parser_t;
|
||||||
|
|
||||||
struct cressi_goa_parser_t {
|
struct cressi_goa_parser_t {
|
||||||
dc_parser_t base;
|
dc_parser_t base;
|
||||||
unsigned int model;
|
unsigned int model;
|
||||||
// Cached fields.
|
|
||||||
unsigned int cached;
|
|
||||||
double maxdepth;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||||
static dc_status_t cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
static dc_status_t cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||||
static dc_status_t cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
static dc_status_t cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||||
@ -63,22 +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 = {
|
static const dc_parser_vtable_t cressi_goa_parser_vtable = {
|
||||||
sizeof(cressi_goa_parser_t),
|
sizeof(cressi_goa_parser_t),
|
||||||
DC_FAMILY_CRESSI_GOA,
|
DC_FAMILY_CRESSI_GOA,
|
||||||
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_datetime, /* datetime */
|
||||||
cressi_goa_parser_get_field, /* fields */
|
cressi_goa_parser_get_field, /* fields */
|
||||||
cressi_goa_parser_samples_foreach, /* samples_foreach */
|
cressi_goa_parser_samples_foreach, /* samples_foreach */
|
||||||
NULL /* destroy */
|
NULL /* destroy */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const unsigned int headersizes[] = {
|
static const cressi_goa_layout_t layouts[] = {
|
||||||
SZ_HEADER_SCUBA,
|
/* SCUBA */
|
||||||
SZ_HEADER_SCUBA,
|
{
|
||||||
SZ_HEADER_FREEDIVE,
|
0x61, /* headersize */
|
||||||
SZ_HEADER_GAUGE,
|
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
|
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;
|
cressi_goa_parser_t *parser = NULL;
|
||||||
|
|
||||||
@ -86,33 +134,19 @@ cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int
|
|||||||
return DC_STATUS_INVALIDARGS;
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
// Allocate memory.
|
// Allocate memory.
|
||||||
parser = (cressi_goa_parser_t *) dc_parser_allocate (context, &cressi_goa_parser_vtable);
|
parser = (cressi_goa_parser_t *) dc_parser_allocate (context, &cressi_goa_parser_vtable, data, size);
|
||||||
if (parser == NULL) {
|
if (parser == NULL) {
|
||||||
ERROR (context, "Failed to allocate memory.");
|
ERROR (context, "Failed to allocate memory.");
|
||||||
return DC_STATUS_NOMEMORY;
|
return DC_STATUS_NOMEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
parser->model = model;
|
parser->model = model;
|
||||||
parser->cached = 0;
|
|
||||||
parser->maxdepth = 0.0;
|
|
||||||
|
|
||||||
*out = (dc_parser_t*) parser;
|
*out = (dc_parser_t*) parser;
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static dc_status_t
|
|
||||||
cressi_goa_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
|
||||||
{
|
|
||||||
cressi_goa_parser_t *parser = (cressi_goa_parser_t *) abstract;
|
|
||||||
|
|
||||||
// Reset the cache.
|
|
||||||
parser->cached = 0;
|
|
||||||
parser->maxdepth = 0.0;
|
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static dc_status_t
|
static dc_status_t
|
||||||
cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||||
{
|
{
|
||||||
@ -123,15 +157,16 @@ cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
|||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
|
||||||
unsigned int divemode = data[2];
|
unsigned int divemode = data[2];
|
||||||
if (divemode >= C_ARRAY_SIZE(headersizes)) {
|
if (divemode >= C_ARRAY_SIZE(layouts)) {
|
||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int headersize = headersizes[divemode];
|
const cressi_goa_layout_t *layout = &layouts[divemode];
|
||||||
if (size < headersize)
|
|
||||||
|
if (size < layout->headersize)
|
||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
|
||||||
const unsigned char *p = abstract->data + 0x11;
|
const unsigned char *p = abstract->data + layout->datetime;
|
||||||
|
|
||||||
if (datetime) {
|
if (datetime) {
|
||||||
datetime->year = array_uint16_le(p);
|
datetime->year = array_uint16_le(p);
|
||||||
@ -149,7 +184,6 @@ cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
|||||||
static dc_status_t
|
static dc_status_t
|
||||||
cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
|
cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value)
|
||||||
{
|
{
|
||||||
cressi_goa_parser_t *parser = (cressi_goa_parser_t *) abstract;
|
|
||||||
const unsigned char *data = abstract->data;
|
const unsigned char *data = abstract->data;
|
||||||
unsigned int size = abstract->size;
|
unsigned int size = abstract->size;
|
||||||
|
|
||||||
@ -157,23 +191,22 @@ cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
|||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
|
||||||
unsigned int divemode = data[2];
|
unsigned int divemode = data[2];
|
||||||
if (divemode >= C_ARRAY_SIZE(headersizes)) {
|
if (divemode >= C_ARRAY_SIZE(layouts)) {
|
||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int headersize = headersizes[divemode];
|
const cressi_goa_layout_t *layout = &layouts[divemode];
|
||||||
if (size < headersize)
|
|
||||||
|
if (size < layout->headersize)
|
||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
|
||||||
if (!parser->cached) {
|
unsigned int ngasmixes = 0;
|
||||||
sample_statistics_t statistics = SAMPLE_STATISTICS_INITIALIZER;
|
if (layout->gasmix != UNDEFINED) {
|
||||||
dc_status_t rc = cressi_goa_parser_samples_foreach (
|
for (unsigned int i = 0; i < NGASMIXES; ++i) {
|
||||||
abstract, sample_statistics_cb, &statistics);
|
if (data[layout->gasmix + 2 * i + 1] == 0)
|
||||||
if (rc != DC_STATUS_SUCCESS)
|
break;
|
||||||
return rc;
|
ngasmixes++;
|
||||||
|
}
|
||||||
parser->cached = 1;
|
|
||||||
parser->maxdepth = statistics.maxdepth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||||
@ -181,17 +214,37 @@ cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
|||||||
if (value) {
|
if (value) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case DC_FIELD_DIVETIME:
|
case DC_FIELD_DIVETIME:
|
||||||
*((unsigned int *) value) = array_uint16_le (data + 0x19);
|
if (layout->divetime == UNDEFINED)
|
||||||
|
return DC_STATUS_UNSUPPORTED;
|
||||||
|
*((unsigned int *) value) = array_uint16_le (data + layout->divetime);
|
||||||
break;
|
break;
|
||||||
case DC_FIELD_MAXDEPTH:
|
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;
|
break;
|
||||||
case DC_FIELD_GASMIX_COUNT:
|
case DC_FIELD_GASMIX_COUNT:
|
||||||
*((unsigned int *) value) = divemode == SCUBA || divemode == NITROX ? 2 : 0;
|
*((unsigned int *) value) = ngasmixes;
|
||||||
break;
|
break;
|
||||||
case DC_FIELD_GASMIX:
|
case DC_FIELD_GASMIX:
|
||||||
|
gasmix->usage = DC_USAGE_NONE;
|
||||||
gasmix->helium = 0.0;
|
gasmix->helium = 0.0;
|
||||||
gasmix->oxygen = data[0x20 + 2 * flags] / 100.0;
|
gasmix->oxygen = data[layout->gasmix + 2 * flags + 1] / 100.0;
|
||||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||||
break;
|
break;
|
||||||
case DC_FIELD_DIVEMODE:
|
case DC_FIELD_DIVEMODE:
|
||||||
@ -228,12 +281,13 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
|||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
|
||||||
unsigned int divemode = data[2];
|
unsigned int divemode = data[2];
|
||||||
if (divemode >= C_ARRAY_SIZE(headersizes)) {
|
if (divemode >= C_ARRAY_SIZE(layouts)) {
|
||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int headersize = headersizes[divemode];
|
const cressi_goa_layout_t *layout = &layouts[divemode];
|
||||||
if (size < headersize)
|
|
||||||
|
if (size < layout->headersize)
|
||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
|
||||||
unsigned int interval = divemode == FREEDIVE ? 2 : 5;
|
unsigned int interval = divemode == FREEDIVE ? 2 : 5;
|
||||||
@ -245,7 +299,7 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
|||||||
unsigned int have_temperature = 0;
|
unsigned int have_temperature = 0;
|
||||||
unsigned int complete = 0;
|
unsigned int complete = 0;
|
||||||
|
|
||||||
unsigned int offset = headersize;
|
unsigned int offset = layout->headersize;
|
||||||
while (offset + 2 <= size) {
|
while (offset + 2 <= size) {
|
||||||
dc_sample_value_t sample = {0};
|
dc_sample_value_t sample = {0};
|
||||||
|
|
||||||
@ -268,25 +322,25 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
|||||||
|
|
||||||
if (complete) {
|
if (complete) {
|
||||||
// Time (seconds).
|
// Time (seconds).
|
||||||
sample.time = time;
|
sample.time = time * 1000;
|
||||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||||
|
|
||||||
// Temperature (1/10 °C).
|
// Temperature (1/10 °C).
|
||||||
if (have_temperature) {
|
if (have_temperature) {
|
||||||
sample.temperature = temperature / 10.0;
|
sample.temperature = temperature / 10.0;
|
||||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||||
have_temperature = 0;
|
have_temperature = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depth (1/10 m).
|
// Depth (1/10 m).
|
||||||
sample.depth = depth / 10.0;
|
sample.depth = depth / 10.0;
|
||||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||||
|
|
||||||
// Gas change
|
// Gas change
|
||||||
if (divemode == SCUBA || divemode == NITROX) {
|
if (divemode == SCUBA || divemode == NITROX) {
|
||||||
if (gasmix != gasmix_previous) {
|
if (gasmix != gasmix_previous) {
|
||||||
sample.gasmix = gasmix;
|
sample.gasmix = gasmix;
|
||||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||||
gasmix_previous = gasmix;
|
gasmix_previous = gasmix;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
#define RB_PROFILE_BEGIN 0x1438
|
#define RB_PROFILE_BEGIN 0x1438
|
||||||
#define RB_PROFILE_END SZ_MEMORY
|
#define RB_PROFILE_END SZ_MEMORY
|
||||||
#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, 0, RB_PROFILE_BEGIN, RB_PROFILE_END)
|
#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_EMPTY, RB_PROFILE_BEGIN, RB_PROFILE_END)
|
||||||
|
|
||||||
#define MAXRETRIES 4
|
#define MAXRETRIES 4
|
||||||
#define PACKETSIZE 32
|
#define PACKETSIZE 32
|
||||||
@ -84,7 +84,7 @@ cressi_leonardo_make_ascii (const unsigned char raw[], unsigned int rsize, unsig
|
|||||||
array_convert_bin2hex (raw, rsize, ascii + 1, 2 * rsize);
|
array_convert_bin2hex (raw, rsize, ascii + 1, 2 * rsize);
|
||||||
|
|
||||||
// Checksum
|
// Checksum
|
||||||
unsigned short crc = checksum_crc16_ccitt (ascii + 1, 2 * rsize, 0xffff);
|
unsigned short crc = checksum_crc16_ccitt (ascii + 1, 2 * rsize, 0xffff, 0x0000);
|
||||||
unsigned char checksum[] = {
|
unsigned char checksum[] = {
|
||||||
(crc >> 8) & 0xFF, // High
|
(crc >> 8) & 0xFF, // High
|
||||||
(crc ) & 0xFF}; // Low
|
(crc ) & 0xFF}; // Low
|
||||||
@ -129,7 +129,7 @@ cressi_leonardo_packet (cressi_leonardo_device_t *device, const unsigned char co
|
|||||||
|
|
||||||
// Verify the checksum of the packet.
|
// Verify the checksum of the packet.
|
||||||
unsigned short crc = array_uint16_be (checksum);
|
unsigned short crc = array_uint16_be (checksum);
|
||||||
unsigned short ccrc = checksum_crc16_ccitt (answer + 1, asize - 6, 0xffff);
|
unsigned short ccrc = checksum_crc16_ccitt (answer + 1, asize - 6, 0xffff, 0x0000);
|
||||||
if (crc != ccrc) {
|
if (crc != ccrc) {
|
||||||
ERROR (abstract->context, "Unexpected answer checksum.");
|
ERROR (abstract->context, "Unexpected answer checksum.");
|
||||||
return DC_STATUS_PROTOCOL;
|
return DC_STATUS_PROTOCOL;
|
||||||
@ -372,12 +372,19 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
|||||||
|
|
||||||
// Verify the checksum.
|
// Verify the checksum.
|
||||||
unsigned int csum1 = array_uint16_be (checksum);
|
unsigned int csum1 = array_uint16_be (checksum);
|
||||||
unsigned int csum2 = checksum_crc16_ccitt (data, SZ_MEMORY, 0xffff);
|
unsigned int csum2 = checksum_crc16_ccitt (data, SZ_MEMORY, 0xffff, 0x0000);
|
||||||
if (csum1 != csum2) {
|
if (csum1 != csum2) {
|
||||||
ERROR (abstract->context, "Unexpected answer bytes.");
|
ERROR (abstract->context, "Unexpected answer bytes.");
|
||||||
return DC_STATUS_PROTOCOL;
|
return DC_STATUS_PROTOCOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Emit a device info event.
|
||||||
|
dc_event_devinfo_t devinfo;
|
||||||
|
devinfo.model = data[0];
|
||||||
|
devinfo.firmware = 0;
|
||||||
|
devinfo.serial = array_uint24_le (data + 1);
|
||||||
|
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,13 +401,6 @@ cressi_leonardo_device_foreach (dc_device_t *abstract, dc_dive_callback_t callba
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char *data = dc_buffer_get_data (buffer);
|
|
||||||
dc_event_devinfo_t devinfo;
|
|
||||||
devinfo.model = data[0];
|
|
||||||
devinfo.firmware = 0;
|
|
||||||
devinfo.serial = array_uint24_le (data + 1);
|
|
||||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
|
||||||
|
|
||||||
rc = cressi_leonardo_extract_dives (abstract, dc_buffer_get_data (buffer),
|
rc = cressi_leonardo_extract_dives (abstract, dc_buffer_get_data (buffer),
|
||||||
dc_buffer_get_size (buffer), callback, userdata);
|
dc_buffer_get_size (buffer), callback, userdata);
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,7 @@ dc_status_t
|
|||||||
cressi_leonardo_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
cressi_leonardo_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
cressi_leonardo_parser_create (dc_parser_t **parser, dc_context_t *context, 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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,7 +39,6 @@ struct cressi_leonardo_parser_t {
|
|||||||
unsigned int model;
|
unsigned int model;
|
||||||
};
|
};
|
||||||
|
|
||||||
static dc_status_t cressi_leonardo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
|
||||||
static dc_status_t cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
static dc_status_t cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||||
static dc_status_t cressi_leonardo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
static dc_status_t cressi_leonardo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||||
static dc_status_t cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
static dc_status_t cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||||
@ -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 = {
|
static const dc_parser_vtable_t cressi_leonardo_parser_vtable = {
|
||||||
sizeof(cressi_leonardo_parser_t),
|
sizeof(cressi_leonardo_parser_t),
|
||||||
DC_FAMILY_CRESSI_LEONARDO,
|
DC_FAMILY_CRESSI_LEONARDO,
|
||||||
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_datetime, /* datetime */
|
||||||
cressi_leonardo_parser_get_field, /* fields */
|
cressi_leonardo_parser_get_field, /* fields */
|
||||||
cressi_leonardo_parser_samples_foreach, /* samples_foreach */
|
cressi_leonardo_parser_samples_foreach, /* samples_foreach */
|
||||||
@ -56,7 +57,7 @@ static const dc_parser_vtable_t cressi_leonardo_parser_vtable = {
|
|||||||
|
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, 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;
|
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;
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
// Allocate memory.
|
// 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) {
|
if (parser == NULL) {
|
||||||
ERROR (context, "Failed to allocate memory.");
|
ERROR (context, "Failed to allocate memory.");
|
||||||
return DC_STATUS_NOMEMORY;
|
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
|
static dc_status_t
|
||||||
cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||||
{
|
{
|
||||||
@ -143,6 +137,7 @@ cressi_leonardo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, u
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DC_FIELD_GASMIX:
|
case DC_FIELD_GASMIX:
|
||||||
|
gasmix->usage = DC_USAGE_NONE;
|
||||||
gasmix->helium = 0.0;
|
gasmix->helium = 0.0;
|
||||||
gasmix->oxygen = data[0x19] / 100.0;
|
gasmix->oxygen = data[0x19] / 100.0;
|
||||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||||
@ -178,6 +173,9 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
|||||||
|
|
||||||
unsigned int gasmix_previous = 0xFFFFFFFF;
|
unsigned int gasmix_previous = 0xFFFFFFFF;
|
||||||
unsigned int gasmix = 0;
|
unsigned int gasmix = 0;
|
||||||
|
if (parser->model == DRAKE) {
|
||||||
|
gasmix = gasmix_previous;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int offset = SZ_HEADER;
|
unsigned int offset = SZ_HEADER;
|
||||||
while (offset + 2 <= size) {
|
while (offset + 2 <= size) {
|
||||||
@ -190,12 +188,12 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
|||||||
|
|
||||||
// Time (seconds).
|
// Time (seconds).
|
||||||
time += surftime;
|
time += surftime;
|
||||||
sample.time = time;
|
sample.time = time * 1000;
|
||||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||||
|
|
||||||
// Depth (1/10 m).
|
// Depth (1/10 m).
|
||||||
sample.depth = 0.0;
|
sample.depth = 0.0;
|
||||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||||
|
|
||||||
offset += 4;
|
offset += 4;
|
||||||
} else {
|
} else {
|
||||||
@ -205,17 +203,17 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
|||||||
|
|
||||||
// Time (seconds).
|
// Time (seconds).
|
||||||
time += interval;
|
time += interval;
|
||||||
sample.time = time;
|
sample.time = time * 1000;
|
||||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||||
|
|
||||||
// Depth (1/10 m).
|
// Depth (1/10 m).
|
||||||
sample.depth = depth / 10.0;
|
sample.depth = depth / 10.0;
|
||||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||||
|
|
||||||
// Gas change.
|
// Gas change.
|
||||||
if (gasmix != gasmix_previous) {
|
if (gasmix != gasmix_previous) {
|
||||||
sample.gasmix = gasmix;
|
sample.gasmix = gasmix;
|
||||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||||
gasmix_previous = gasmix;
|
gasmix_previous = gasmix;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,7 +223,7 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
|||||||
sample.event.time = 0;
|
sample.event.time = 0;
|
||||||
sample.event.flags = 0;
|
sample.event.flags = 0;
|
||||||
sample.event.value = ascent;
|
sample.event.value = ascent;
|
||||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += 2;
|
offset += 2;
|
||||||
|
|||||||
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;
|
||||||
|
}
|
||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
238
src/descriptor.c
238
src/descriptor.c
@ -23,7 +23,10 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.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 "iterator-private.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
@ -36,32 +39,26 @@
|
|||||||
values, \
|
values, \
|
||||||
C_ARRAY_SIZE(values) - isnullterminated, \
|
C_ARRAY_SIZE(values) - isnullterminated, \
|
||||||
C_ARRAY_ITEMSIZE(values), \
|
C_ARRAY_ITEMSIZE(values), \
|
||||||
match, \
|
match)
|
||||||
NULL, NULL, 0)
|
|
||||||
|
|
||||||
#define DC_FILTER_INTERNAL_WITH_PARAMS(key, values, isnullterminated, match, params_dst, params_src) \
|
|
||||||
dc_filter_internal( \
|
|
||||||
key, \
|
|
||||||
values, \
|
|
||||||
C_ARRAY_SIZE(values) - isnullterminated, \
|
|
||||||
C_ARRAY_ITEMSIZE(values), \
|
|
||||||
match, \
|
|
||||||
params_dst, params_src, sizeof *(params_src))
|
|
||||||
|
|
||||||
typedef int (*dc_match_t)(const void *, const void *);
|
typedef int (*dc_match_t)(const void *, const void *);
|
||||||
|
|
||||||
typedef int (*dc_filter_t) (dc_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_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||||
static int dc_filter_suunto (dc_transport_t transport, const void *userdata, void *params);
|
static int dc_filter_suunto (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||||
static int dc_filter_shearwater (dc_transport_t transport, const void *userdata, void *params);
|
static int dc_filter_shearwater (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||||
static int dc_filter_hw (dc_transport_t transport, const void *userdata, void *params);
|
static int dc_filter_hw (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||||
static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata, void *params);
|
static int dc_filter_tecdiving (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||||
static int dc_filter_mares (dc_transport_t transport, const void *userdata, void *params);
|
static int dc_filter_mares (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||||
static int dc_filter_divesystem (dc_transport_t transport, const void *userdata, void *params);
|
static int dc_filter_divesystem (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||||
static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, void *params);
|
static int dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||||
static int dc_filter_mclean (dc_transport_t transport, const void *userdata, void *params);
|
static int dc_filter_mclean (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||||
static int dc_filter_atomic (dc_transport_t transport, const void *userdata, void *params);
|
static int dc_filter_atomic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||||
|
static int dc_filter_deepsix (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||||
|
static int dc_filter_deepblu (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||||
|
static int dc_filter_oceans (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||||
|
static int dc_filter_divesoft (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||||
|
|
||||||
static dc_status_t dc_descriptor_iterator_next (dc_iterator_t *iterator, void *item);
|
static dc_status_t dc_descriptor_iterator_next (dc_iterator_t *iterator, void *item);
|
||||||
|
|
||||||
@ -170,9 +167,13 @@ static const dc_descriptor_t g_descriptors[] = {
|
|||||||
{"Scubapro", "Aladin A1", DC_FAMILY_UWATEC_SMART, 0x25, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
{"Scubapro", "Aladin A1", DC_FAMILY_UWATEC_SMART, 0x25, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||||
{"Scubapro", "Mantis 2", DC_FAMILY_UWATEC_SMART, 0x26, DC_TRANSPORT_SERIAL, NULL},
|
{"Scubapro", "Mantis 2", DC_FAMILY_UWATEC_SMART, 0x26, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Scubapro", "Aladin A2", DC_FAMILY_UWATEC_SMART, 0x28, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
{"Scubapro", "Aladin A2", DC_FAMILY_UWATEC_SMART, 0x28, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||||
|
{"Scubapro", "G2 TEK", DC_FAMILY_UWATEC_SMART, 0x31, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||||
{"Scubapro", "G2", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
{"Scubapro", "G2", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||||
{"Scubapro", "G2 Console", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
{"Scubapro", "G2 Console", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||||
|
{"Scubapro", "G3", DC_FAMILY_UWATEC_SMART, 0x34, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||||
{"Scubapro", "G2 HUD", DC_FAMILY_UWATEC_SMART, 0x42, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
{"Scubapro", "G2 HUD", DC_FAMILY_UWATEC_SMART, 0x42, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||||
|
{"Scubapro", "Luna 2.0 AI", DC_FAMILY_UWATEC_SMART, 0x50, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||||
|
{"Scubapro", "Luna 2.0", DC_FAMILY_UWATEC_SMART, 0x51, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||||
/* Reefnet */
|
/* Reefnet */
|
||||||
{"Reefnet", "Sensus", DC_FAMILY_REEFNET_SENSUS, 1, DC_TRANSPORT_SERIAL, NULL},
|
{"Reefnet", "Sensus", DC_FAMILY_REEFNET_SENSUS, 1, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Reefnet", "Sensus Pro", DC_FAMILY_REEFNET_SENSUSPRO, 2, DC_TRANSPORT_SERIAL, NULL},
|
{"Reefnet", "Sensus Pro", DC_FAMILY_REEFNET_SENSUSPRO, 2, DC_TRANSPORT_SERIAL, NULL},
|
||||||
@ -251,7 +252,7 @@ static const dc_descriptor_t g_descriptors[] = {
|
|||||||
{"Sherwood", "Vision", DC_FAMILY_OCEANIC_ATOM2, 0x4556, DC_TRANSPORT_SERIAL, NULL},
|
{"Sherwood", "Vision", DC_FAMILY_OCEANIC_ATOM2, 0x4556, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Oceanic", "VTX", DC_FAMILY_OCEANIC_ATOM2, 0x4557, DC_TRANSPORT_SERIAL, NULL},
|
{"Oceanic", "VTX", DC_FAMILY_OCEANIC_ATOM2, 0x4557, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Aqualung", "i300", DC_FAMILY_OCEANIC_ATOM2, 0x4559, DC_TRANSPORT_SERIAL, NULL},
|
{"Aqualung", "i300", DC_FAMILY_OCEANIC_ATOM2, 0x4559, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Aqualung", "i750TC", DC_FAMILY_OCEANIC_ATOM2, 0x455A, DC_TRANSPORT_SERIAL, 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", "i450T", DC_FAMILY_OCEANIC_ATOM2, 0x4641, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Aqualung", "i550", DC_FAMILY_OCEANIC_ATOM2, 0x4642, DC_TRANSPORT_SERIAL, NULL},
|
{"Aqualung", "i550", DC_FAMILY_OCEANIC_ATOM2, 0x4642, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Aqualung", "i200", DC_FAMILY_OCEANIC_ATOM2, 0x4646, DC_TRANSPORT_SERIAL, NULL},
|
{"Aqualung", "i200", DC_FAMILY_OCEANIC_ATOM2, 0x4646, DC_TRANSPORT_SERIAL, NULL},
|
||||||
@ -266,8 +267,14 @@ static const dc_descriptor_t g_descriptors[] = {
|
|||||||
{"Sherwood", "Wisdom 4", DC_FAMILY_OCEANIC_ATOM2, 0x4655, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
{"Sherwood", "Wisdom 4", DC_FAMILY_OCEANIC_ATOM2, 0x4655, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||||
{"Oceanic", "Pro Plus 4", DC_FAMILY_OCEANIC_ATOM2, 0x4656, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
{"Oceanic", "Pro Plus 4", DC_FAMILY_OCEANIC_ATOM2, 0x4656, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||||
{"Sherwood", "Amphos 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4657, DC_TRANSPORT_SERIAL, NULL},
|
{"Sherwood", "Amphos 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4657, DC_TRANSPORT_SERIAL, NULL},
|
||||||
|
{"Sherwood", "Amphos Air 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4658, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Sherwood", "Beacon", DC_FAMILY_OCEANIC_ATOM2, 0x4742, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
{"Sherwood", "Beacon", DC_FAMILY_OCEANIC_ATOM2, 0x4742, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||||
{"Aqualung", "i470TC", DC_FAMILY_OCEANIC_ATOM2, 0x4743, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
{"Aqualung", "i470TC", DC_FAMILY_OCEANIC_ATOM2, 0x4743, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||||
|
{"Aqualung", "i200C", DC_FAMILY_OCEANIC_ATOM2, 0x4749, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||||
|
{"Oceanic", "Geo Air", DC_FAMILY_OCEANIC_ATOM2, 0x474B, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||||
|
/* Pelagic I330R */
|
||||||
|
{"Apeks", "DSX", DC_FAMILY_PELAGIC_I330R, 0x4741, DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||||
|
{"Aqualung", "i330R", DC_FAMILY_PELAGIC_I330R, 0x4744, DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||||
/* Mares Nemo */
|
/* Mares Nemo */
|
||||||
{"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
|
{"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
|
{"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||||
@ -292,6 +299,7 @@ static const dc_descriptor_t g_descriptors[] = {
|
|||||||
{"Mares", "Icon HD", DC_FAMILY_MARES_ICONHD , 0x14, DC_TRANSPORT_SERIAL, NULL},
|
{"Mares", "Icon HD", DC_FAMILY_MARES_ICONHD , 0x14, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Mares", "Icon HD Net Ready", DC_FAMILY_MARES_ICONHD , 0x15, DC_TRANSPORT_SERIAL, NULL},
|
{"Mares", "Icon HD Net Ready", DC_FAMILY_MARES_ICONHD , 0x15, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Mares", "Puck Pro", DC_FAMILY_MARES_ICONHD , 0x18, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
{"Mares", "Puck Pro", DC_FAMILY_MARES_ICONHD , 0x18, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
||||||
|
{"Mares", "Puck Pro +", DC_FAMILY_MARES_ICONHD , 0x18, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
||||||
{"Mares", "Nemo Wide 2", DC_FAMILY_MARES_ICONHD , 0x19, DC_TRANSPORT_SERIAL, NULL},
|
{"Mares", "Nemo Wide 2", DC_FAMILY_MARES_ICONHD , 0x19, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Mares", "Genius", DC_FAMILY_MARES_ICONHD , 0x1C, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
{"Mares", "Genius", DC_FAMILY_MARES_ICONHD , 0x1C, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
|
||||||
{"Mares", "Puck 2", DC_FAMILY_MARES_ICONHD , 0x1F, DC_TRANSPORT_SERIAL, NULL},
|
{"Mares", "Puck 2", DC_FAMILY_MARES_ICONHD , 0x1F, DC_TRANSPORT_SERIAL, NULL},
|
||||||
@ -299,6 +307,10 @@ static const dc_descriptor_t g_descriptors[] = {
|
|||||||
{"Mares", "Smart Air", DC_FAMILY_MARES_ICONHD , 0x24, 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", "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},
|
{"Mares", "Horizon", DC_FAMILY_MARES_ICONHD , 0x2C, DC_TRANSPORT_SERIAL, NULL},
|
||||||
|
{"Mares", "Puck Air 2", DC_FAMILY_MARES_ICONHD , 0x2D, DC_TRANSPORT_BLE, dc_filter_mares},
|
||||||
|
{"Mares", "Sirius", DC_FAMILY_MARES_ICONHD , 0x2F, DC_TRANSPORT_BLE, dc_filter_mares},
|
||||||
|
{"Mares", "Quad Ci", DC_FAMILY_MARES_ICONHD , 0x31, DC_TRANSPORT_BLE, dc_filter_mares},
|
||||||
|
{"Mares", "Puck 4", DC_FAMILY_MARES_ICONHD , 0x35, DC_TRANSPORT_BLE, dc_filter_mares},
|
||||||
/* Heinrichs Weikamp */
|
/* Heinrichs Weikamp */
|
||||||
{"Heinrichs Weikamp", "OSTC", DC_FAMILY_HW_OSTC, 0, DC_TRANSPORT_SERIAL, NULL},
|
{"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},
|
{"Heinrichs Weikamp", "OSTC Mk2", DC_FAMILY_HW_OSTC, 1, DC_TRANSPORT_SERIAL, NULL},
|
||||||
@ -328,6 +340,9 @@ static const dc_descriptor_t g_descriptors[] = {
|
|||||||
/* Cressi Goa */
|
/* Cressi Goa */
|
||||||
{"Cressi", "Cartesio", DC_FAMILY_CRESSI_GOA, 1, DC_TRANSPORT_SERIAL, NULL},
|
{"Cressi", "Cartesio", DC_FAMILY_CRESSI_GOA, 1, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Cressi", "Goa", DC_FAMILY_CRESSI_GOA, 2, 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 */
|
||||||
{"Zeagle", "N2iTiON3", DC_FAMILY_ZEAGLE_N2ITION3, 0, DC_TRANSPORT_SERIAL, NULL},
|
{"Zeagle", "N2iTiON3", DC_FAMILY_ZEAGLE_N2ITION3, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Apeks", "Quantum X", DC_FAMILY_ZEAGLE_N2ITION3, 0, DC_TRANSPORT_SERIAL, NULL},
|
{"Apeks", "Quantum X", DC_FAMILY_ZEAGLE_N2ITION3, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||||
@ -347,6 +362,9 @@ static const dc_descriptor_t g_descriptors[] = {
|
|||||||
{"Shearwater", "Nerd 2", DC_FAMILY_SHEARWATER_PETREL, 7, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
{"Shearwater", "Nerd 2", DC_FAMILY_SHEARWATER_PETREL, 7, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||||
{"Shearwater", "Teric", DC_FAMILY_SHEARWATER_PETREL, 8, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
{"Shearwater", "Teric", DC_FAMILY_SHEARWATER_PETREL, 8, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||||
{"Shearwater", "Peregrine", DC_FAMILY_SHEARWATER_PETREL, 9, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
{"Shearwater", "Peregrine", DC_FAMILY_SHEARWATER_PETREL, 9, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||||
|
{"Shearwater", "Petrel 3", DC_FAMILY_SHEARWATER_PETREL, 10, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||||
|
{"Shearwater", "Perdix 2", DC_FAMILY_SHEARWATER_PETREL, 11, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||||
|
{"Shearwater", "Tern", DC_FAMILY_SHEARWATER_PETREL, 12, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||||
/* Dive Rite NiTek Q */
|
/* Dive Rite NiTek Q */
|
||||||
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0, DC_TRANSPORT_SERIAL, NULL},
|
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||||
/* Citizen Hyper Aqualand */
|
/* Citizen Hyper Aqualand */
|
||||||
@ -400,6 +418,25 @@ static const dc_descriptor_t g_descriptors[] = {
|
|||||||
{"Ratio", "iX3M 2021 Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x73, DC_TRANSPORT_SERIAL, NULL},
|
{"Ratio", "iX3M 2021 Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x73, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Ratio", "iX3M 2021 Pro Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x74, DC_TRANSPORT_SERIAL, NULL},
|
{"Ratio", "iX3M 2021 Pro Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x74, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Ratio", "iX3M 2021 Pro Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x75, DC_TRANSPORT_SERIAL, NULL},
|
{"Ratio", "iX3M 2021 Pro Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x75, DC_TRANSPORT_SERIAL, NULL},
|
||||||
|
{"Ratio", "iDive 2 Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x80, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iDive 2 Fancy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x81, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iDive 2 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x82, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iDive 2 Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x83, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iDive 2 Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x84, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iDive 2 Tech", DC_FAMILY_DIVESYSTEM_IDIVE, 0x85, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iDive 2 Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x86, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iX3M 2 GPS Gauge", DC_FAMILY_DIVESYSTEM_IDIVE, 0x90, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iX3M 2 GPS Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x91, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iX3M 2 GPS Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x92, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iX3M 2 GPS Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x93, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iX3M 2 GPS Tech", DC_FAMILY_DIVESYSTEM_IDIVE, 0x94, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iX3M 2 GPS Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x95, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "ATOM", DC_FAMILY_DIVESYSTEM_IDIVE, 0x96, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iX3M 2 Gauge", DC_FAMILY_DIVESYSTEM_IDIVE, 0x100, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iX3M 2 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x101, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iX3M 2 Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x102, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iX3M 2 Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x103, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
|
{"Ratio", "iX3M 2 Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x104, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||||
{"Seac", "Jack", DC_FAMILY_DIVESYSTEM_IDIVE, 0x1000, DC_TRANSPORT_SERIAL, NULL},
|
{"Seac", "Jack", DC_FAMILY_DIVESYSTEM_IDIVE, 0x1000, DC_TRANSPORT_SERIAL, NULL},
|
||||||
{"Seac", "Guru", DC_FAMILY_DIVESYSTEM_IDIVE, 0x1002, DC_TRANSPORT_SERIAL, NULL},
|
{"Seac", "Guru", DC_FAMILY_DIVESYSTEM_IDIVE, 0x1002, DC_TRANSPORT_SERIAL, NULL},
|
||||||
/* Cochran Commander */
|
/* Cochran Commander */
|
||||||
@ -420,6 +457,21 @@ static const dc_descriptor_t g_descriptors[] = {
|
|||||||
{"Liquivision", "Kaon", DC_FAMILY_LIQUIVISION_LYNX, 3, DC_TRANSPORT_SERIAL, NULL},
|
{"Liquivision", "Kaon", DC_FAMILY_LIQUIVISION_LYNX, 3, DC_TRANSPORT_SERIAL, NULL},
|
||||||
/* Sporasub */
|
/* Sporasub */
|
||||||
{"Sporasub", "SP2", DC_FAMILY_SPORASUB_SP2, 0, DC_TRANSPORT_SERIAL, NULL},
|
{"Sporasub", "SP2", DC_FAMILY_SPORASUB_SP2, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||||
|
/* Deep Six Excursion */
|
||||||
|
{"Deep Six", "Excursion", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||||
|
{"Crest", "CR-4", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||||
|
{"Genesis", "Centauri", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||||
|
{"Scorpena", "Alpha", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||||
|
/* Seac Screen */
|
||||||
|
{"Seac", "Screen", DC_FAMILY_SEAC_SCREEN, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||||
|
{"Seac", "Action", DC_FAMILY_SEAC_SCREEN, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||||
|
/* Deepblu Cosmiq */
|
||||||
|
{"Deepblu", "Cosmiq+", DC_FAMILY_DEEPBLU_COSMIQ, 0, DC_TRANSPORT_BLE, dc_filter_deepblu},
|
||||||
|
/* Oceans S1 */
|
||||||
|
{"Oceans", "S1", DC_FAMILY_OCEANS_S1, 0, DC_TRANSPORT_BLE, dc_filter_oceans},
|
||||||
|
/* Divesoft Freedom */
|
||||||
|
{"Divesoft", "Freedom", DC_FAMILY_DIVESOFT_FREEDOM, 19, DC_TRANSPORT_BLE, dc_filter_divesoft},
|
||||||
|
{"Divesoft", "Liberty", DC_FAMILY_DIVESOFT_FREEDOM, 10, DC_TRANSPORT_BLE, dc_filter_divesoft},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -458,6 +510,15 @@ dc_match_usb (const void *key, const void *value)
|
|||||||
return k->vid == v->vid && k->pid == v->pid;
|
return k->vid == v->vid && k->pid == v->pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dc_match_usbhid (const void *key, const void *value)
|
||||||
|
{
|
||||||
|
const dc_usbhid_desc_t *k = (const dc_usbhid_desc_t *) key;
|
||||||
|
const dc_usbhid_desc_t *v = (const dc_usbhid_desc_t *) value;
|
||||||
|
|
||||||
|
return k->vid == v->vid && k->pid == v->pid;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
dc_match_number_with_prefix (const void *key, const void *value)
|
dc_match_number_with_prefix (const void *key, const void *value)
|
||||||
{
|
{
|
||||||
@ -498,16 +559,13 @@ dc_match_oceanic (const void *key, const void *value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
dc_filter_internal (const void *key, const void *values, size_t count, size_t size, dc_match_t match, 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)
|
if (key == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
for (size_t i = 0; i < count; ++i) {
|
for (size_t i = 0; i < count; ++i) {
|
||||||
if (match (key, (const unsigned char *) values + i * size)) {
|
if (match (key, (const unsigned char *) values + i * size)) {
|
||||||
if (params_src && params_dst) {
|
|
||||||
memcpy (params_dst, params_src, params_size);
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -522,7 +580,8 @@ static const char * const rfcomm[] = {
|
|||||||
NULL
|
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[] = {
|
static const char * const irda[] = {
|
||||||
"Aladin Smart Com",
|
"Aladin Smart Com",
|
||||||
@ -533,8 +592,8 @@ static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, voi
|
|||||||
"UWATEC Galileo",
|
"UWATEC Galileo",
|
||||||
"UWATEC Galileo Sol",
|
"UWATEC Galileo Sol",
|
||||||
};
|
};
|
||||||
static const dc_usb_desc_t usbhid[] = {
|
static const dc_usbhid_desc_t usbhid[] = {
|
||||||
{0x2e6c, 0x3201}, // G2
|
{0x2e6c, 0x3201}, // G2, G2 TEK
|
||||||
{0x2e6c, 0x3211}, // G2 Console
|
{0x2e6c, 0x3211}, // G2 Console
|
||||||
{0x2e6c, 0x4201}, // G2 HUD
|
{0x2e6c, 0x4201}, // G2 HUD
|
||||||
{0xc251, 0x2006}, // Aladin Square
|
{0xc251, 0x2006}, // Aladin Square
|
||||||
@ -545,12 +604,16 @@ static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, voi
|
|||||||
"HUD",
|
"HUD",
|
||||||
"A1",
|
"A1",
|
||||||
"A2",
|
"A2",
|
||||||
|
"G2 TEK",
|
||||||
|
"Galileo 3",
|
||||||
|
"Luna 2.0 AI",
|
||||||
|
"Luna 2.0",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (transport == DC_TRANSPORT_IRDA) {
|
if (transport == DC_TRANSPORT_IRDA) {
|
||||||
return DC_FILTER_INTERNAL (userdata, irda, 0, dc_match_name);
|
return DC_FILTER_INTERNAL (userdata, irda, 0, dc_match_name);
|
||||||
} else if (transport == DC_TRANSPORT_USBHID) {
|
} else if (transport == DC_TRANSPORT_USBHID) {
|
||||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usb);
|
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usbhid);
|
||||||
} else if (transport == DC_TRANSPORT_BLE) {
|
} else if (transport == DC_TRANSPORT_BLE) {
|
||||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name);
|
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name);
|
||||||
}
|
}
|
||||||
@ -558,9 +621,10 @@ static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, voi
|
|||||||
return 1;
|
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, 0x0030}, // Eon Steel
|
||||||
{0x1493, 0x0033}, // Eon Core
|
{0x1493, 0x0033}, // Eon Core
|
||||||
{0x1493, 0x0035}, // D5
|
{0x1493, 0x0035}, // D5
|
||||||
@ -574,7 +638,7 @@ static int dc_filter_suunto (dc_transport_t transport, const void *userdata, voi
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (transport == DC_TRANSPORT_USBHID) {
|
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) {
|
} else if (transport == DC_TRANSPORT_BLE) {
|
||||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix);
|
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix);
|
||||||
}
|
}
|
||||||
@ -582,7 +646,8 @@ static int dc_filter_suunto (dc_transport_t transport, const void *userdata, voi
|
|||||||
return 1;
|
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[] = {
|
static const char * const bluetooth[] = {
|
||||||
"OSTC",
|
"OSTC",
|
||||||
@ -598,16 +663,20 @@ static int dc_filter_hw (dc_transport_t transport, const void *userdata, void *p
|
|||||||
return 1;
|
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[] = {
|
static const char * const bluetooth[] = {
|
||||||
"Predator",
|
"Predator",
|
||||||
"Petrel",
|
"Petrel",
|
||||||
|
"Petrel 3",
|
||||||
"NERD",
|
"NERD",
|
||||||
"NERD 2",
|
"NERD 2",
|
||||||
"Perdix",
|
"Perdix",
|
||||||
|
"Perdix 2",
|
||||||
"Teric",
|
"Teric",
|
||||||
"Peregrine",
|
"Peregrine",
|
||||||
|
"Tern"
|
||||||
};
|
};
|
||||||
|
|
||||||
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
|
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
|
||||||
@ -619,7 +688,8 @@ static int dc_filter_shearwater (dc_transport_t transport, const void *userdata,
|
|||||||
return 1;
|
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[] = {
|
static const char * const bluetooth[] = {
|
||||||
"DiveComputer",
|
"DiveComputer",
|
||||||
@ -634,11 +704,15 @@ static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata,
|
|||||||
return 1;
|
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[] = {
|
static const char * const bluetooth[] = {
|
||||||
"Mares bluelink pro",
|
"Mares bluelink pro",
|
||||||
"Mares Genius",
|
"Mares Genius",
|
||||||
|
"Sirius",
|
||||||
|
"Quad Ci",
|
||||||
|
"Puck4",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (transport == DC_TRANSPORT_BLE) {
|
if (transport == DC_TRANSPORT_BLE) {
|
||||||
@ -648,11 +722,13 @@ static int dc_filter_mares (dc_transport_t transport, const void *userdata, void
|
|||||||
return 1;
|
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[] = {
|
static const char * const bluetooth[] = {
|
||||||
"DS",
|
"DS",
|
||||||
"IX5M",
|
"IX5M",
|
||||||
|
"RATIO-",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
|
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
|
||||||
@ -662,10 +738,12 @@ static int dc_filter_divesystem (dc_transport_t transport, const void *userdata,
|
|||||||
return 1;
|
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[] = {
|
static const unsigned int model[] = {
|
||||||
0x4552, // Oceanic Pro Plus X
|
0x4552, // Oceanic Pro Plus X
|
||||||
|
0x455A, // Aqualung i750TC
|
||||||
0x4647, // Sherwood Sage
|
0x4647, // Sherwood Sage
|
||||||
0x4648, // Aqualung i300C
|
0x4648, // Aqualung i300C
|
||||||
0x4649, // Aqualung i200C
|
0x4649, // Aqualung i200C
|
||||||
@ -675,8 +753,12 @@ static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, vo
|
|||||||
0x4654, // Oceanic Veo 4.0
|
0x4654, // Oceanic Veo 4.0
|
||||||
0x4655, // Sherwood Wisdom 4
|
0x4655, // Sherwood Wisdom 4
|
||||||
0x4656, // Oceanic Pro Plus 4
|
0x4656, // Oceanic Pro Plus 4
|
||||||
|
0x4741, // Apeks DSX
|
||||||
0x4742, // Sherwood Beacon
|
0x4742, // Sherwood Beacon
|
||||||
0x4743, // Aqualung i470TC
|
0x4743, // Aqualung i470TC
|
||||||
|
0x4744, // Aqualung i330R
|
||||||
|
0x4749, // Aqualung i200C
|
||||||
|
0x474B, // Oceanic Geo Air
|
||||||
};
|
};
|
||||||
|
|
||||||
if (transport == DC_TRANSPORT_BLE) {
|
if (transport == DC_TRANSPORT_BLE) {
|
||||||
@ -686,7 +768,8 @@ static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, vo
|
|||||||
return 1;
|
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[] = {
|
static const char * const bluetooth[] = {
|
||||||
"McLean Extreme",
|
"McLean Extreme",
|
||||||
@ -701,18 +784,75 @@ static int dc_filter_mclean(dc_transport_t transport, const void *userdata, void
|
|||||||
return 1;
|
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[] = {
|
static const dc_usb_desc_t usb[] = {
|
||||||
{0x0471, 0x0888}, // Atomic Aquatics Cobalt
|
{0x0471, 0x0888}, // Atomic Aquatics Cobalt
|
||||||
};
|
};
|
||||||
|
|
||||||
static const dc_usb_params_t usb_params = {
|
if (transport == DC_TRANSPORT_USB) {
|
||||||
0, 0x82, 0x02
|
return DC_FILTER_INTERNAL (userdata, usb, 0, dc_match_usb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dc_filter_deepsix (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||||
|
{
|
||||||
|
static const char * const bluetooth[] = {
|
||||||
|
"EXCURSION",
|
||||||
|
"Crest-CR4",
|
||||||
|
"CENTAURI",
|
||||||
|
"ALPHA",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (transport == DC_TRANSPORT_USB) {
|
if (transport == DC_TRANSPORT_BLE) {
|
||||||
return DC_FILTER_INTERNAL_WITH_PARAMS (userdata, usb, 0, dc_match_usb, params, &usb_params);
|
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dc_filter_deepblu (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||||
|
{
|
||||||
|
static const char * const bluetooth[] = {
|
||||||
|
"COSMIQ",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (transport == DC_TRANSPORT_BLE) {
|
||||||
|
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dc_filter_oceans (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||||
|
{
|
||||||
|
static const char * const bluetooth[] = {
|
||||||
|
"S1",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (transport == DC_TRANSPORT_BLE) {
|
||||||
|
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dc_filter_divesoft (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||||
|
{
|
||||||
|
static const char * const bluetooth[] = {
|
||||||
|
"Freedom",
|
||||||
|
"Liberty",
|
||||||
|
};
|
||||||
|
|
||||||
|
if (transport == DC_TRANSPORT_BLE) {
|
||||||
|
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -810,10 +950,10 @@ dc_descriptor_get_transports (dc_descriptor_t *descriptor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata, void *params)
|
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||||
{
|
{
|
||||||
if (descriptor == NULL || descriptor->filter == NULL || userdata == NULL)
|
if (descriptor == NULL || descriptor->filter == NULL || userdata == NULL)
|
||||||
return 1;
|
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);
|
device_is_cancelled (dc_device_t *device);
|
||||||
|
|
||||||
dc_status_t
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
33
src/device.c
33
src/device.c
@ -38,6 +38,7 @@
|
|||||||
#include "oceanic_atom2.h"
|
#include "oceanic_atom2.h"
|
||||||
#include "oceanic_veo250.h"
|
#include "oceanic_veo250.h"
|
||||||
#include "oceanic_vtpro.h"
|
#include "oceanic_vtpro.h"
|
||||||
|
#include "pelagic_i330r.h"
|
||||||
#include "mares_darwin.h"
|
#include "mares_darwin.h"
|
||||||
#include "mares_iconhd.h"
|
#include "mares_iconhd.h"
|
||||||
#include "mares_nemo.h"
|
#include "mares_nemo.h"
|
||||||
@ -60,6 +61,11 @@
|
|||||||
#include "mclean_extreme.h"
|
#include "mclean_extreme.h"
|
||||||
#include "liquivision_lynx.h"
|
#include "liquivision_lynx.h"
|
||||||
#include "sporasub_sp2.h"
|
#include "sporasub_sp2.h"
|
||||||
|
#include "deepsix_excursion.h"
|
||||||
|
#include "seac_screen.h"
|
||||||
|
#include "deepblu_cosmiq.h"
|
||||||
|
#include "oceans_s1.h"
|
||||||
|
#include "divesoft_freedom.h"
|
||||||
|
|
||||||
#include "device-private.h"
|
#include "device-private.h"
|
||||||
#include "context-private.h"
|
#include "context-private.h"
|
||||||
@ -157,6 +163,9 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
|
|||||||
case DC_FAMILY_OCEANIC_ATOM2:
|
case DC_FAMILY_OCEANIC_ATOM2:
|
||||||
rc = oceanic_atom2_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
rc = oceanic_atom2_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
||||||
break;
|
break;
|
||||||
|
case DC_FAMILY_PELAGIC_I330R:
|
||||||
|
rc = pelagic_i330r_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
||||||
|
break;
|
||||||
case DC_FAMILY_MARES_NEMO:
|
case DC_FAMILY_MARES_NEMO:
|
||||||
rc = mares_nemo_device_open (&device, context, iostream);
|
rc = mares_nemo_device_open (&device, context, iostream);
|
||||||
break;
|
break;
|
||||||
@ -167,7 +176,7 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
|
|||||||
rc = mares_darwin_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
rc = mares_darwin_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
||||||
break;
|
break;
|
||||||
case DC_FAMILY_MARES_ICONHD:
|
case DC_FAMILY_MARES_ICONHD:
|
||||||
rc = mares_iconhd_device_open (&device, context, iostream);
|
rc = mares_iconhd_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
||||||
break;
|
break;
|
||||||
case DC_FAMILY_HW_OSTC:
|
case DC_FAMILY_HW_OSTC:
|
||||||
rc = hw_ostc_device_open (&device, context, iostream);
|
rc = hw_ostc_device_open (&device, context, iostream);
|
||||||
@ -223,6 +232,21 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
|
|||||||
case DC_FAMILY_SPORASUB_SP2:
|
case DC_FAMILY_SPORASUB_SP2:
|
||||||
rc = sporasub_sp2_device_open (&device, context, iostream);
|
rc = sporasub_sp2_device_open (&device, context, iostream);
|
||||||
break;
|
break;
|
||||||
|
case DC_FAMILY_DEEPSIX_EXCURSION:
|
||||||
|
rc = deepsix_excursion_device_open (&device, context, iostream);
|
||||||
|
break;
|
||||||
|
case DC_FAMILY_SEAC_SCREEN:
|
||||||
|
rc = seac_screen_device_open (&device, context, iostream);
|
||||||
|
break;
|
||||||
|
case DC_FAMILY_DEEPBLU_COSMIQ:
|
||||||
|
rc = deepblu_cosmiq_device_open (&device, context, iostream);
|
||||||
|
break;
|
||||||
|
case DC_FAMILY_OCEANS_S1:
|
||||||
|
rc = oceans_s1_device_open (&device, context, iostream);
|
||||||
|
break;
|
||||||
|
case DC_FAMILY_DIVESOFT_FREEDOM:
|
||||||
|
rc = divesoft_freedom_device_open (&device, context, iostream);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return DC_STATUS_INVALIDARGS;
|
return DC_STATUS_INVALIDARGS;
|
||||||
}
|
}
|
||||||
@ -338,7 +362,7 @@ dc_device_dump (dc_device_t *device, dc_buffer_t *buffer)
|
|||||||
|
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
device_dump_read (dc_device_t *device, unsigned 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)
|
if (device == NULL)
|
||||||
return DC_STATUS_UNSUPPORTED;
|
return DC_STATUS_UNSUPPORTED;
|
||||||
@ -359,7 +383,7 @@ device_dump_read (dc_device_t *device, unsigned char data[], unsigned int size,
|
|||||||
len = blocksize;
|
len = blocksize;
|
||||||
|
|
||||||
// Read the packet.
|
// 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)
|
if (rc != DC_STATUS_SUCCESS)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -396,6 +420,9 @@ dc_device_timesync (dc_device_t *device, const dc_datetime_t *datetime)
|
|||||||
if (device->vtable->timesync == NULL)
|
if (device->vtable->timesync == NULL)
|
||||||
return DC_STATUS_UNSUPPORTED;
|
return DC_STATUS_UNSUPPORTED;
|
||||||
|
|
||||||
|
if (datetime == NULL)
|
||||||
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
return device->vtable->timesync (device, datetime);
|
return device->vtable->timesync (device, datetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -35,7 +35,7 @@ dc_status_t
|
|||||||
diverite_nitekq_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
diverite_nitekq_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
diverite_nitekq_parser_create (dc_parser_t **parser, dc_context_t *context);
|
diverite_nitekq_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,7 +49,6 @@ struct diverite_nitekq_parser_t {
|
|||||||
double maxdepth;
|
double maxdepth;
|
||||||
};
|
};
|
||||||
|
|
||||||
static dc_status_t diverite_nitekq_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
|
||||||
static dc_status_t diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
static dc_status_t diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||||
static dc_status_t diverite_nitekq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
static dc_status_t diverite_nitekq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||||
static dc_status_t diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
static dc_status_t diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||||
@ -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 = {
|
static const dc_parser_vtable_t diverite_nitekq_parser_vtable = {
|
||||||
sizeof(diverite_nitekq_parser_t),
|
sizeof(diverite_nitekq_parser_t),
|
||||||
DC_FAMILY_DIVERITE_NITEKQ,
|
DC_FAMILY_DIVERITE_NITEKQ,
|
||||||
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_datetime, /* datetime */
|
||||||
diverite_nitekq_parser_get_field, /* fields */
|
diverite_nitekq_parser_get_field, /* fields */
|
||||||
diverite_nitekq_parser_samples_foreach, /* samples_foreach */
|
diverite_nitekq_parser_samples_foreach, /* samples_foreach */
|
||||||
@ -66,7 +67,7 @@ static const dc_parser_vtable_t diverite_nitekq_parser_vtable = {
|
|||||||
|
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context)
|
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;
|
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;
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
// Allocate memory.
|
// 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) {
|
if (parser == NULL) {
|
||||||
ERROR (context, "Failed to allocate memory.");
|
ERROR (context, "Failed to allocate memory.");
|
||||||
return DC_STATUS_NOMEMORY;
|
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
|
static dc_status_t
|
||||||
diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||||
{
|
{
|
||||||
@ -158,6 +152,7 @@ diverite_nitekq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, u
|
|||||||
*((unsigned int *) value) = parser->ngasmixes;
|
*((unsigned int *) value) = parser->ngasmixes;
|
||||||
break;
|
break;
|
||||||
case DC_FIELD_GASMIX:
|
case DC_FIELD_GASMIX:
|
||||||
|
gasmix->usage = DC_USAGE_NONE;
|
||||||
gasmix->helium = parser->he[flags] / 100.0;
|
gasmix->helium = parser->he[flags] / 100.0;
|
||||||
gasmix->oxygen = parser->o2[flags] / 100.0;
|
gasmix->oxygen = parser->o2[flags] / 100.0;
|
||||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||||
@ -261,13 +256,13 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
|||||||
|
|
||||||
// Time (seconds).
|
// Time (seconds).
|
||||||
time += interval;
|
time += interval;
|
||||||
sample.time = time;
|
sample.time = time * 1000;
|
||||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||||
|
|
||||||
// Gas change
|
// Gas change
|
||||||
if (gasmix != gasmix_previous) {
|
if (gasmix != gasmix_previous) {
|
||||||
sample.gasmix = gasmix;
|
sample.gasmix = gasmix;
|
||||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||||
gasmix_previous = gasmix;
|
gasmix_previous = gasmix;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,7 +274,7 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
|||||||
sample.depth = depth / 10.0;
|
sample.depth = depth / 10.0;
|
||||||
else
|
else
|
||||||
sample.depth = depth * FEET / 10.0;
|
sample.depth = depth * FEET / 10.0;
|
||||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
|
|
||||||
if (type == 3) {
|
if (type == 3) {
|
||||||
@ -290,8 +285,9 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
|||||||
if (offset + 1 > size)
|
if (offset + 1 > size)
|
||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
unsigned int ppo2 = data[offset];
|
unsigned int ppo2 = data[offset];
|
||||||
sample.ppo2 = ppo2 / 100.0;
|
sample.ppo2.sensor = DC_SENSOR_NONE;
|
||||||
if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
|
sample.ppo2.value = ppo2 / 100.0;
|
||||||
|
if (callback) callback (DC_SAMPLE_PPO2, &sample, userdata);
|
||||||
offset++;
|
offset++;
|
||||||
}
|
}
|
||||||
} else {
|
} 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 */
|
||||||
1044
src/divesoft_freedom_parser.c
Normal file
1044
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 "platform.h"
|
||||||
#include "checksum.h"
|
#include "checksum.h"
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
|
#include "packet.h"
|
||||||
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
|
|
||||||
|
|
||||||
#define ISINSTANCE(device) dc_device_isinstance((device), &divesystem_idive_device_vtable)
|
#define ISINSTANCE(device) dc_device_isinstance((device), &divesystem_idive_device_vtable)
|
||||||
|
|
||||||
@ -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_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||||
static dc_status_t divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
static dc_status_t divesystem_idive_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
|
||||||
static dc_status_t divesystem_idive_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime);
|
static dc_status_t divesystem_idive_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime);
|
||||||
|
static dc_status_t divesystem_idive_device_close (dc_device_t *abstract);
|
||||||
|
|
||||||
static const dc_device_vtable_t divesystem_idive_device_vtable = {
|
static const dc_device_vtable_t divesystem_idive_device_vtable = {
|
||||||
sizeof(divesystem_idive_device_t),
|
sizeof(divesystem_idive_device_t),
|
||||||
@ -114,7 +114,7 @@ static const dc_device_vtable_t divesystem_idive_device_vtable = {
|
|||||||
NULL, /* dump */
|
NULL, /* dump */
|
||||||
divesystem_idive_device_foreach, /* foreach */
|
divesystem_idive_device_foreach, /* foreach */
|
||||||
divesystem_idive_device_timesync, /* timesync */
|
divesystem_idive_device_timesync, /* timesync */
|
||||||
NULL /* close */
|
divesystem_idive_device_close /* close */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const divesystem_idive_commands_t idive = {
|
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;
|
dc_status_t status = DC_STATUS_SUCCESS;
|
||||||
divesystem_idive_device_t *device = NULL;
|
divesystem_idive_device_t *device = NULL;
|
||||||
|
dc_transport_t transport = dc_iostream_get_transport (iostream);
|
||||||
|
|
||||||
if (out == NULL)
|
if (out == NULL)
|
||||||
return DC_STATUS_INVALIDARGS;
|
return DC_STATUS_INVALIDARGS;
|
||||||
@ -166,22 +167,32 @@ divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, dc_iostr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the default values.
|
// Set the default values.
|
||||||
device->iostream = iostream;
|
|
||||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||||
device->model = model;
|
device->model = model;
|
||||||
|
|
||||||
|
// Create the packet stream.
|
||||||
|
if (transport == DC_TRANSPORT_BLE) {
|
||||||
|
status = dc_packet_open (&device->iostream, context, iostream, 244, 244);
|
||||||
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
|
ERROR (context, "Failed to create the packet stream.");
|
||||||
|
goto error_free;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
device->iostream = iostream;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the serial communication protocol (115200 8N1).
|
// Set the serial communication protocol (115200 8N1).
|
||||||
status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
|
status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
ERROR (context, "Failed to set the terminal attributes.");
|
ERROR (context, "Failed to set the terminal attributes.");
|
||||||
goto error_free;
|
goto error_free_iostream;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the timeout for receiving data (1000ms).
|
// Set the timeout for receiving data (1000ms).
|
||||||
status = dc_iostream_set_timeout (device->iostream, 1000);
|
status = dc_iostream_set_timeout (device->iostream, 1000);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
ERROR (context, "Failed to set the timeout.");
|
ERROR (context, "Failed to set the timeout.");
|
||||||
goto error_free;
|
goto error_free_iostream;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure everything is in a sane state.
|
// 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;
|
return DC_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
error_free_iostream:
|
||||||
|
if (transport == DC_TRANSPORT_BLE) {
|
||||||
|
dc_iostream_close (device->iostream);
|
||||||
|
}
|
||||||
error_free:
|
error_free:
|
||||||
dc_device_deallocate ((dc_device_t *) device);
|
dc_device_deallocate ((dc_device_t *) device);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
divesystem_idive_device_close (dc_device_t *abstract)
|
||||||
|
{
|
||||||
|
divesystem_idive_device_t *device = (divesystem_idive_device_t *) abstract;
|
||||||
|
|
||||||
|
// Close the packet stream.
|
||||||
|
if (dc_iostream_get_transport (device->iostream) == DC_TRANSPORT_BLE) {
|
||||||
|
return dc_iostream_close (device->iostream);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DC_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static dc_status_t
|
static dc_status_t
|
||||||
divesystem_idive_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
|
divesystem_idive_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size)
|
||||||
@ -233,7 +260,7 @@ divesystem_idive_send (divesystem_idive_device_t *device, const unsigned char co
|
|||||||
packet[0] = START;
|
packet[0] = START;
|
||||||
packet[1] = csize;
|
packet[1] = csize;
|
||||||
memcpy(packet + 2, command, csize);
|
memcpy(packet + 2, command, csize);
|
||||||
crc = checksum_crc16_ccitt (packet, csize + 2, 0xffff);
|
crc = checksum_crc16_ccitt (packet, csize + 2, 0xffff, 0x0000);
|
||||||
packet[csize + 2] = (crc >> 8) & 0xFF;
|
packet[csize + 2] = (crc >> 8) & 0xFF;
|
||||||
packet[csize + 3] = (crc ) & 0xFF;
|
packet[csize + 3] = (crc ) & 0xFF;
|
||||||
|
|
||||||
@ -294,7 +321,7 @@ divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answe
|
|||||||
|
|
||||||
// Verify the checksum.
|
// Verify the checksum.
|
||||||
unsigned short crc = array_uint16_be (packet + len + 2);
|
unsigned short crc = array_uint16_be (packet + len + 2);
|
||||||
unsigned short ccrc = checksum_crc16_ccitt (packet, len + 2, 0xffff);
|
unsigned short ccrc = checksum_crc16_ccitt (packet, len + 2, 0xffff, 0x0000);
|
||||||
if (crc != ccrc) {
|
if (crc != ccrc) {
|
||||||
ERROR (abstract->context, "Unexpected packet checksum.");
|
ERROR (abstract->context, "Unexpected packet checksum.");
|
||||||
return DC_STATUS_PROTOCOL;
|
return DC_STATUS_PROTOCOL;
|
||||||
@ -610,11 +637,6 @@ divesystem_idive_device_timesync (dc_device_t *abstract, const dc_datetime_t *da
|
|||||||
return DC_STATUS_UNSUPPORTED;
|
return DC_STATUS_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (datetime == NULL) {
|
|
||||||
ERROR (abstract->context, "Invalid parameter specified.");
|
|
||||||
return DC_STATUS_INVALIDARGS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the UTC timestamp.
|
// Get the UTC timestamp.
|
||||||
dc_ticks_t timestamp = dc_datetime_mktime(datetime);
|
dc_ticks_t timestamp = dc_datetime_mktime(datetime);
|
||||||
if (timestamp == -1) {
|
if (timestamp == -1) {
|
||||||
|
|||||||
@ -36,7 +36,7 @@ dc_status_t
|
|||||||
divesystem_idive_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
|
divesystem_idive_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
divesystem_idive_parser_create (dc_parser_t **parser, dc_context_t *context, 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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,11 +26,10 @@
|
|||||||
#include "parser-private.h"
|
#include "parser-private.h"
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
|
|
||||||
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
|
|
||||||
|
|
||||||
#define ISINSTANCE(parser) dc_device_isinstance((parser), &divesystem_idive_parser_vtable)
|
#define ISINSTANCE(parser) dc_device_isinstance((parser), &divesystem_idive_parser_vtable)
|
||||||
|
|
||||||
#define ISIX3M(model) ((model) >= 0x21)
|
#define ISIX3M(model) ((model) >= 0x21)
|
||||||
|
#define ISIX3M2(model) ((model) >= 0x60 && (model) < 0x1000)
|
||||||
|
|
||||||
#define SZ_HEADER_IDIVE 0x32
|
#define SZ_HEADER_IDIVE 0x32
|
||||||
#define SZ_SAMPLE_IDIVE 0x2A
|
#define SZ_SAMPLE_IDIVE 0x2A
|
||||||
@ -50,6 +49,18 @@
|
|||||||
#define FREEDIVE 4
|
#define FREEDIVE 4
|
||||||
#define INVALID 0xFFFFFFFF
|
#define INVALID 0xFFFFFFFF
|
||||||
|
|
||||||
|
#define BUHLMANN 0
|
||||||
|
#define VPM 1
|
||||||
|
#define DUAL 2
|
||||||
|
|
||||||
|
#define IX3M2_BUHLMANN 0
|
||||||
|
#define IX3M2_ZHL16B 1
|
||||||
|
#define IX3M2_ZHL16C 2
|
||||||
|
#define IX3M2_VPM 3
|
||||||
|
|
||||||
|
#define REC_SAMPLE 0
|
||||||
|
#define REC_INFO 1
|
||||||
|
|
||||||
typedef struct divesystem_idive_parser_t divesystem_idive_parser_t;
|
typedef struct divesystem_idive_parser_t divesystem_idive_parser_t;
|
||||||
|
|
||||||
typedef struct divesystem_idive_gasmix_t {
|
typedef struct divesystem_idive_gasmix_t {
|
||||||
@ -76,9 +87,11 @@ struct divesystem_idive_parser_t {
|
|||||||
unsigned int ntanks;
|
unsigned int ntanks;
|
||||||
divesystem_idive_gasmix_t gasmix[NGASMIXES];
|
divesystem_idive_gasmix_t gasmix[NGASMIXES];
|
||||||
divesystem_idive_tank_t tank[NTANKS];
|
divesystem_idive_tank_t tank[NTANKS];
|
||||||
|
unsigned int algorithm;
|
||||||
|
unsigned int gf_low;
|
||||||
|
unsigned int gf_high;
|
||||||
};
|
};
|
||||||
|
|
||||||
static dc_status_t divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
|
||||||
static dc_status_t divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
static dc_status_t divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||||
static dc_status_t divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
static dc_status_t divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||||
static dc_status_t divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
static dc_status_t divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||||
@ -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 = {
|
static const dc_parser_vtable_t divesystem_idive_parser_vtable = {
|
||||||
sizeof(divesystem_idive_parser_t),
|
sizeof(divesystem_idive_parser_t),
|
||||||
DC_FAMILY_DIVESYSTEM_IDIVE,
|
DC_FAMILY_DIVESYSTEM_IDIVE,
|
||||||
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_datetime, /* datetime */
|
||||||
divesystem_idive_parser_get_field, /* fields */
|
divesystem_idive_parser_get_field, /* fields */
|
||||||
divesystem_idive_parser_samples_foreach, /* samples_foreach */
|
divesystem_idive_parser_samples_foreach, /* samples_foreach */
|
||||||
@ -95,7 +110,7 @@ static const dc_parser_vtable_t divesystem_idive_parser_vtable = {
|
|||||||
|
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, 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;
|
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;
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
// Allocate memory.
|
// 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) {
|
if (parser == NULL) {
|
||||||
ERROR (context, "Failed to allocate memory.");
|
ERROR (context, "Failed to allocate memory.");
|
||||||
return DC_STATUS_NOMEMORY;
|
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].beginpressure = 0;
|
||||||
parser->tank[i].endpressure = 0;
|
parser->tank[i].endpressure = 0;
|
||||||
}
|
}
|
||||||
|
parser->algorithm = INVALID;
|
||||||
|
parser->gf_low = INVALID;
|
||||||
|
parser->gf_high = INVALID;
|
||||||
|
|
||||||
|
|
||||||
*out = (dc_parser_t*) parser;
|
*out = (dc_parser_t*) parser;
|
||||||
|
|
||||||
@ -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
|
static dc_status_t
|
||||||
divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||||
{
|
{
|
||||||
@ -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_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||||
dc_tank_t *tank = (dc_tank_t *) value;
|
dc_tank_t *tank = (dc_tank_t *) value;
|
||||||
dc_salinity_t *water = (dc_salinity_t *) value;
|
dc_salinity_t *water = (dc_salinity_t *) value;
|
||||||
|
dc_decomodel_t *decomodel = (dc_decomodel_t *) value;
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -295,6 +289,7 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
|||||||
*((unsigned int *) value) = parser->ngasmixes;
|
*((unsigned int *) value) = parser->ngasmixes;
|
||||||
break;
|
break;
|
||||||
case DC_FIELD_GASMIX:
|
case DC_FIELD_GASMIX:
|
||||||
|
gasmix->usage = DC_USAGE_NONE;
|
||||||
gasmix->helium = parser->gasmix[flags].helium / 100.0;
|
gasmix->helium = parser->gasmix[flags].helium / 100.0;
|
||||||
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
|
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
|
||||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||||
@ -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->beginpressure = parser->tank[flags].beginpressure;
|
||||||
tank->endpressure = parser->tank[flags].endpressure;
|
tank->endpressure = parser->tank[flags].endpressure;
|
||||||
tank->gasmix = DC_GASMIX_UNKNOWN;
|
tank->gasmix = DC_GASMIX_UNKNOWN;
|
||||||
|
tank->usage = DC_USAGE_NONE;
|
||||||
break;
|
break;
|
||||||
case DC_FIELD_ATMOSPHERIC:
|
case DC_FIELD_ATMOSPHERIC:
|
||||||
if (ISIX3M(parser->model)) {
|
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;
|
water->density = 0.0;
|
||||||
break;
|
break;
|
||||||
case DC_FIELD_DIVEMODE:
|
case DC_FIELD_DIVEMODE:
|
||||||
if (parser->divemode == 0xFFFFFFFF)
|
if (parser->divemode == INVALID)
|
||||||
return DC_STATUS_UNSUPPORTED;
|
return DC_STATUS_UNSUPPORTED;
|
||||||
switch (parser->divemode) {
|
switch (parser->divemode) {
|
||||||
case OC:
|
case OC:
|
||||||
@ -345,6 +341,46 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
|||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DC_FIELD_DECOMODEL:
|
||||||
|
if (parser->algorithm == INVALID)
|
||||||
|
return DC_STATUS_UNSUPPORTED;
|
||||||
|
if (ISIX3M2(parser->model)) {
|
||||||
|
switch (parser->algorithm) {
|
||||||
|
case IX3M2_BUHLMANN:
|
||||||
|
case IX3M2_ZHL16B:
|
||||||
|
case IX3M2_ZHL16C:
|
||||||
|
decomodel->type = DC_DECOMODEL_BUHLMANN;
|
||||||
|
decomodel->conservatism = 0;
|
||||||
|
decomodel->params.gf.low = parser->gf_low;
|
||||||
|
decomodel->params.gf.high = parser->gf_high;
|
||||||
|
break;
|
||||||
|
case IX3M2_VPM:
|
||||||
|
decomodel->type = DC_DECOMODEL_VPM;
|
||||||
|
decomodel->conservatism = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR (abstract->context, "Unknown deco algorithm %02x.", parser->algorithm);
|
||||||
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (parser->algorithm) {
|
||||||
|
case BUHLMANN:
|
||||||
|
case DUAL:
|
||||||
|
decomodel->type = DC_DECOMODEL_BUHLMANN;
|
||||||
|
decomodel->conservatism = 0;
|
||||||
|
decomodel->params.gf.low = parser->gf_low;
|
||||||
|
decomodel->params.gf.high = parser->gf_high;
|
||||||
|
break;
|
||||||
|
case VPM:
|
||||||
|
decomodel->type = DC_DECOMODEL_VPM;
|
||||||
|
decomodel->conservatism = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ERROR (abstract->context, "Unknown deco algorithm %02x.", parser->algorithm);
|
||||||
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return DC_STATUS_UNSUPPORTED;
|
return DC_STATUS_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
@ -367,12 +403,17 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
|||||||
unsigned int ntanks = 0;
|
unsigned int ntanks = 0;
|
||||||
divesystem_idive_gasmix_t gasmix[NGASMIXES] = {0};
|
divesystem_idive_gasmix_t gasmix[NGASMIXES] = {0};
|
||||||
divesystem_idive_tank_t tank[NTANKS] = {0};
|
divesystem_idive_tank_t tank[NTANKS] = {0};
|
||||||
unsigned int o2_previous = 0xFFFFFFFF;
|
unsigned int o2_previous = INVALID;
|
||||||
unsigned int he_previous = 0xFFFFFFFF;
|
unsigned int he_previous = INVALID;
|
||||||
unsigned int mode_previous = INVALID;
|
unsigned int mode_previous = INVALID;
|
||||||
unsigned int divemode = INVALID;
|
unsigned int divemode = INVALID;
|
||||||
unsigned int tank_previous = INVALID;
|
unsigned int tank_previous = INVALID;
|
||||||
unsigned int tank_idx = INVALID;
|
unsigned int tank_idx = INVALID;
|
||||||
|
unsigned int algorithm = INVALID;
|
||||||
|
unsigned int algorithm_previous = INVALID;
|
||||||
|
unsigned int gf_low = INVALID;
|
||||||
|
unsigned int gf_high = INVALID;
|
||||||
|
unsigned int have_bearing = 0;
|
||||||
|
|
||||||
unsigned int firmware = 0;
|
unsigned int firmware = 0;
|
||||||
unsigned int apos4 = 0;
|
unsigned int apos4 = 0;
|
||||||
@ -401,27 +442,37 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
|||||||
while (offset + samplesize <= size) {
|
while (offset + samplesize <= size) {
|
||||||
dc_sample_value_t sample = {0};
|
dc_sample_value_t sample = {0};
|
||||||
|
|
||||||
|
// Get the record type.
|
||||||
|
unsigned int type = ISIX3M(parser->model) ?
|
||||||
|
array_uint16_le (data + offset + 52) :
|
||||||
|
REC_SAMPLE;
|
||||||
|
if (type != REC_SAMPLE) {
|
||||||
|
// Skip non-sample records.
|
||||||
|
offset += samplesize;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Time (seconds).
|
// Time (seconds).
|
||||||
unsigned int timestamp = array_uint32_le (data + offset + 2);
|
unsigned int timestamp = array_uint32_le (data + offset + 2);
|
||||||
if (timestamp <= time) {
|
if (timestamp <= time && time != 0) {
|
||||||
ERROR (abstract->context, "Timestamp moved backwards.");
|
ERROR (abstract->context, "Timestamp moved backwards (%u %u).", timestamp, time);
|
||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
time = timestamp;
|
time = timestamp;
|
||||||
sample.time = timestamp;
|
sample.time = timestamp * 1000;
|
||||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||||
|
|
||||||
// Depth (1/10 m).
|
// Depth (1/10 m).
|
||||||
unsigned int depth = array_uint16_le (data + offset + 6);
|
unsigned int depth = array_uint16_le (data + offset + 6);
|
||||||
if (maxdepth < depth)
|
if (maxdepth < depth)
|
||||||
maxdepth = depth;
|
maxdepth = depth;
|
||||||
sample.depth = depth / 10.0;
|
sample.depth = depth / 10.0;
|
||||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||||
|
|
||||||
// Temperature (Celsius).
|
// Temperature (Celsius).
|
||||||
signed int temperature = (signed short) array_uint16_le (data + offset + 8);
|
signed int temperature = (signed short) array_uint16_le (data + offset + 8);
|
||||||
sample.temperature = temperature / 10.0;
|
sample.temperature = temperature / 10.0;
|
||||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||||
|
|
||||||
// Dive mode
|
// Dive mode
|
||||||
unsigned int mode = data[offset + 18];
|
unsigned int mode = data[offset + 18];
|
||||||
@ -435,11 +486,27 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
|||||||
divemode = mode;
|
divemode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deco model
|
||||||
|
unsigned int s_algorithm = data[offset + 14];
|
||||||
|
unsigned int s_gf_high = data[offset + 15];
|
||||||
|
unsigned int s_gf_low = data[offset + 16];
|
||||||
|
if (s_algorithm != algorithm_previous) {
|
||||||
|
if (algorithm_previous != INVALID) {
|
||||||
|
WARNING (abstract->context, "Deco algorithm changed from %02x to %02x.", algorithm_previous, s_algorithm);
|
||||||
|
}
|
||||||
|
algorithm_previous = s_algorithm;
|
||||||
|
}
|
||||||
|
if (algorithm == INVALID) {
|
||||||
|
algorithm = s_algorithm;
|
||||||
|
gf_low = s_gf_low;
|
||||||
|
gf_high = s_gf_high;
|
||||||
|
}
|
||||||
|
|
||||||
// Setpoint
|
// Setpoint
|
||||||
if (mode == SCR || mode == CCR) {
|
if (mode == SCR || mode == CCR) {
|
||||||
unsigned int setpoint = array_uint16_le (data + offset + 19);
|
unsigned int setpoint = array_uint16_le (data + offset + 19);
|
||||||
sample.setpoint = setpoint / 1000.0;
|
sample.setpoint = setpoint / 1000.0;
|
||||||
if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
|
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gaschange.
|
// Gaschange.
|
||||||
@ -466,7 +533,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
|||||||
}
|
}
|
||||||
|
|
||||||
sample.gasmix = i;
|
sample.gasmix = i;
|
||||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||||
o2_previous = o2;
|
o2_previous = o2;
|
||||||
he_previous = he;
|
he_previous = he;
|
||||||
}
|
}
|
||||||
@ -484,18 +551,20 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
|||||||
if (decostop) {
|
if (decostop) {
|
||||||
sample.deco.type = DC_DECO_DECOSTOP;
|
sample.deco.type = DC_DECO_DECOSTOP;
|
||||||
sample.deco.depth = decostop / 10.0;
|
sample.deco.depth = decostop / 10.0;
|
||||||
sample.deco.time = apos4 ? decotime : tts;
|
sample.deco.time = decotime;
|
||||||
|
sample.deco.tts = tts;
|
||||||
} else {
|
} else {
|
||||||
sample.deco.type = DC_DECO_NDL;
|
sample.deco.type = DC_DECO_NDL;
|
||||||
sample.deco.depth = 0.0;
|
sample.deco.depth = 0.0;
|
||||||
sample.deco.time = tts;
|
sample.deco.time = tts;
|
||||||
|
sample.deco.tts = 0;
|
||||||
}
|
}
|
||||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||||
|
|
||||||
// CNS
|
// CNS
|
||||||
unsigned int cns = array_uint16_le (data + offset + 29);
|
unsigned int cns = array_uint16_le (data + offset + 29);
|
||||||
sample.cns = cns / 100.0;
|
sample.cns = cns / 100.0;
|
||||||
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
|
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata);
|
||||||
|
|
||||||
// Tank Pressure
|
// Tank Pressure
|
||||||
if (samplesize == SZ_SAMPLE_IX3M_APOS4) {
|
if (samplesize == SZ_SAMPLE_IX3M_APOS4) {
|
||||||
@ -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 flags = data[offset + 47] & 0xF0;
|
||||||
unsigned int pressure = data[offset + 49];
|
unsigned int pressure = data[offset + 49];
|
||||||
|
|
||||||
|
if (flags & 0x20) {
|
||||||
|
// 300 bar transmitter.
|
||||||
|
pressure *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
if (flags & 0x80) {
|
if (flags & 0x80) {
|
||||||
// No active transmitter available
|
// No active transmitter available
|
||||||
} else if (flags & 0x40) {
|
} else if (flags & 0x40) {
|
||||||
@ -511,7 +585,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
|||||||
sample.event.time = 0;
|
sample.event.time = 0;
|
||||||
sample.event.flags = 0;
|
sample.event.flags = 0;
|
||||||
sample.event.value = 0;
|
sample.event.value = 0;
|
||||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||||
} else {
|
} else {
|
||||||
// Get the index of the tank.
|
// Get the index of the tank.
|
||||||
if (id != tank_previous) {
|
if (id != tank_previous) {
|
||||||
@ -541,10 +615,20 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
|||||||
if (tank_idx < ntanks) {
|
if (tank_idx < ntanks) {
|
||||||
sample.pressure.tank = tank_idx;
|
sample.pressure.tank = tank_idx;
|
||||||
sample.pressure.value = pressure;
|
sample.pressure.value = pressure;
|
||||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||||
tank[tank_idx].endpressure = pressure;
|
tank[tank_idx].endpressure = pressure;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compass bearing
|
||||||
|
unsigned int bearing = array_uint16_le (data + offset + 50);
|
||||||
|
if (bearing != 0) {
|
||||||
|
have_bearing = 1; // Stop ignoring zero values.
|
||||||
|
}
|
||||||
|
if (have_bearing && bearing != 0xFFFF) {
|
||||||
|
sample.bearing = bearing;
|
||||||
|
if (callback) callback (DC_SAMPLE_BEARING, &sample, userdata);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += samplesize;
|
offset += samplesize;
|
||||||
@ -562,6 +646,9 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
|||||||
parser->maxdepth = maxdepth;
|
parser->maxdepth = maxdepth;
|
||||||
parser->divetime = time;
|
parser->divetime = time;
|
||||||
parser->divemode = divemode;
|
parser->divemode = divemode;
|
||||||
|
parser->algorithm = algorithm;
|
||||||
|
parser->gf_low = gf_low;
|
||||||
|
parser->gf_high = gf_high;
|
||||||
parser->cached = 1;
|
parser->cached = 1;
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
|
|||||||
406
src/hdlc.c
Normal file
406
src/hdlc.c
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
/*
|
||||||
|
* libdivecomputer
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Jef Driesen
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h> // malloc, free
|
||||||
|
|
||||||
|
#include "hdlc.h"
|
||||||
|
|
||||||
|
#include "iostream-private.h"
|
||||||
|
#include "common-private.h"
|
||||||
|
#include "context-private.h"
|
||||||
|
|
||||||
|
#define END 0x7E
|
||||||
|
#define ESC 0x7D
|
||||||
|
#define ESC_BIT 0x20
|
||||||
|
|
||||||
|
static dc_status_t dc_hdlc_set_timeout (dc_iostream_t *abstract, int timeout);
|
||||||
|
static dc_status_t dc_hdlc_set_break (dc_iostream_t *abstract, unsigned int value);
|
||||||
|
static dc_status_t dc_hdlc_set_dtr (dc_iostream_t *abstract, unsigned int value);
|
||||||
|
static dc_status_t dc_hdlc_set_rts (dc_iostream_t *abstract, unsigned int value);
|
||||||
|
static dc_status_t dc_hdlc_get_lines (dc_iostream_t *abstract, unsigned int *value);
|
||||||
|
static dc_status_t dc_hdlc_configure (dc_iostream_t *abstract, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol);
|
||||||
|
static dc_status_t dc_hdlc_poll (dc_iostream_t *abstract, int timeout);
|
||||||
|
static dc_status_t dc_hdlc_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual);
|
||||||
|
static dc_status_t dc_hdlc_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual);
|
||||||
|
static dc_status_t dc_hdlc_ioctl (dc_iostream_t *abstract, unsigned int request, void *data, size_t size);
|
||||||
|
static dc_status_t dc_hdlc_flush (dc_iostream_t *abstract);
|
||||||
|
static dc_status_t dc_hdlc_purge (dc_iostream_t *abstract, dc_direction_t direction);
|
||||||
|
static dc_status_t dc_hdlc_sleep (dc_iostream_t *abstract, unsigned int milliseconds);
|
||||||
|
static dc_status_t dc_hdlc_close (dc_iostream_t *abstract);
|
||||||
|
|
||||||
|
typedef struct dc_hdlc_t {
|
||||||
|
/* Base class. */
|
||||||
|
dc_iostream_t base;
|
||||||
|
/* Internal state. */
|
||||||
|
dc_context_t *context;
|
||||||
|
dc_iostream_t *iostream;
|
||||||
|
unsigned char *rbuf;
|
||||||
|
unsigned char *wbuf;
|
||||||
|
size_t rbuf_size;
|
||||||
|
size_t rbuf_offset;
|
||||||
|
size_t rbuf_available;
|
||||||
|
size_t wbuf_size;
|
||||||
|
size_t wbuf_offset;
|
||||||
|
} dc_hdlc_t;
|
||||||
|
|
||||||
|
static const dc_iostream_vtable_t dc_hdlc_vtable = {
|
||||||
|
sizeof(dc_hdlc_t),
|
||||||
|
dc_hdlc_set_timeout, /* set_timeout */
|
||||||
|
dc_hdlc_set_break, /* set_break */
|
||||||
|
dc_hdlc_set_dtr, /* set_dtr */
|
||||||
|
dc_hdlc_set_rts, /* set_rts */
|
||||||
|
dc_hdlc_get_lines, /* get_lines */
|
||||||
|
NULL, /* get_available */
|
||||||
|
dc_hdlc_configure, /* configure */
|
||||||
|
dc_hdlc_poll, /* poll */
|
||||||
|
dc_hdlc_read, /* read */
|
||||||
|
dc_hdlc_write, /* write */
|
||||||
|
dc_hdlc_ioctl, /* ioctl */
|
||||||
|
dc_hdlc_flush, /* flush */
|
||||||
|
dc_hdlc_purge, /* purge */
|
||||||
|
dc_hdlc_sleep, /* sleep */
|
||||||
|
dc_hdlc_close, /* close */
|
||||||
|
};
|
||||||
|
|
||||||
|
dc_status_t
|
||||||
|
dc_hdlc_open (dc_iostream_t **out, dc_context_t *context, dc_iostream_t *base, size_t isize, size_t osize)
|
||||||
|
{
|
||||||
|
dc_status_t status = DC_STATUS_SUCCESS;
|
||||||
|
dc_hdlc_t *hdlc = NULL;
|
||||||
|
|
||||||
|
if (out == NULL)
|
||||||
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
|
if (base == NULL || isize == 0 || osize == 0)
|
||||||
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
|
dc_transport_t transport = dc_iostream_get_transport (base);
|
||||||
|
|
||||||
|
// Allocate memory.
|
||||||
|
hdlc = (dc_hdlc_t *) dc_iostream_allocate (NULL, &dc_hdlc_vtable, transport);
|
||||||
|
if (hdlc == NULL) {
|
||||||
|
ERROR (context, "Failed to allocate memory.");
|
||||||
|
status = DC_STATUS_NOMEMORY;
|
||||||
|
goto error_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the read buffer.
|
||||||
|
hdlc->rbuf = malloc (isize);
|
||||||
|
if (hdlc->rbuf == NULL) {
|
||||||
|
ERROR (context, "Failed to allocate memory.");
|
||||||
|
status = DC_STATUS_NOMEMORY;
|
||||||
|
goto error_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the write buffer.
|
||||||
|
hdlc->wbuf = malloc (osize);
|
||||||
|
if (hdlc->wbuf == NULL) {
|
||||||
|
ERROR (context, "Failed to allocate memory.");
|
||||||
|
status = DC_STATUS_NOMEMORY;
|
||||||
|
goto error_free_rbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdlc->context = context;
|
||||||
|
hdlc->iostream = base;
|
||||||
|
hdlc->rbuf_size = isize;
|
||||||
|
hdlc->rbuf_offset = 0;
|
||||||
|
hdlc->rbuf_available = 0;
|
||||||
|
hdlc->wbuf_size = osize;
|
||||||
|
hdlc->wbuf_offset = 0;
|
||||||
|
|
||||||
|
*out = (dc_iostream_t *) hdlc;
|
||||||
|
|
||||||
|
return DC_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
error_free_rbuf:
|
||||||
|
free (hdlc->rbuf);
|
||||||
|
error_free:
|
||||||
|
dc_iostream_deallocate ((dc_iostream_t *) hdlc);
|
||||||
|
error_exit:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
dc_hdlc_set_timeout (dc_iostream_t *abstract, int timeout)
|
||||||
|
{
|
||||||
|
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||||
|
|
||||||
|
return dc_iostream_set_timeout (hdlc->iostream, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
dc_hdlc_set_break (dc_iostream_t *abstract, unsigned int value)
|
||||||
|
{
|
||||||
|
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||||
|
|
||||||
|
return dc_iostream_set_break (hdlc->iostream, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
dc_hdlc_set_dtr (dc_iostream_t *abstract, unsigned int value)
|
||||||
|
{
|
||||||
|
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||||
|
|
||||||
|
return dc_iostream_set_dtr (hdlc->iostream, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
dc_hdlc_set_rts (dc_iostream_t *abstract, unsigned int value)
|
||||||
|
{
|
||||||
|
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||||
|
|
||||||
|
return dc_iostream_set_rts (hdlc->iostream, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
dc_hdlc_get_lines (dc_iostream_t *abstract, unsigned int *value)
|
||||||
|
{
|
||||||
|
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||||
|
|
||||||
|
return dc_iostream_get_lines (hdlc->iostream, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
dc_hdlc_configure (dc_iostream_t *abstract, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol)
|
||||||
|
{
|
||||||
|
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||||
|
|
||||||
|
return dc_iostream_configure (hdlc->iostream, baudrate, databits, parity, stopbits, flowcontrol);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
dc_hdlc_poll (dc_iostream_t *abstract, int timeout)
|
||||||
|
{
|
||||||
|
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||||
|
|
||||||
|
if (hdlc->rbuf_available) {
|
||||||
|
return DC_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dc_iostream_poll (hdlc->iostream, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
dc_hdlc_read (dc_iostream_t *abstract, void *data, size_t size, size_t *actual)
|
||||||
|
{
|
||||||
|
dc_status_t status = DC_STATUS_SUCCESS;
|
||||||
|
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||||
|
size_t nbytes = 0;
|
||||||
|
|
||||||
|
unsigned int initialized = 0;
|
||||||
|
unsigned int escaped = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (hdlc->rbuf_available == 0) {
|
||||||
|
// Read a packet into the cache.
|
||||||
|
size_t len = 0;
|
||||||
|
status = dc_iostream_read (hdlc->iostream, hdlc->rbuf, hdlc->rbuf_size, &len);
|
||||||
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdlc->rbuf_available = len;
|
||||||
|
hdlc->rbuf_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (hdlc->rbuf_available) {
|
||||||
|
unsigned char c = hdlc->rbuf[hdlc->rbuf_offset];
|
||||||
|
hdlc->rbuf_offset++;
|
||||||
|
hdlc->rbuf_available--;
|
||||||
|
|
||||||
|
if (c == END) {
|
||||||
|
if (escaped) {
|
||||||
|
ERROR (hdlc->context, "HDLC frame escaped the special character %02x.", c);
|
||||||
|
status = DC_STATUS_IO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initialized) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
initialized = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == ESC) {
|
||||||
|
if (escaped) {
|
||||||
|
ERROR (hdlc->context, "HDLC frame escaped the special character %02x.", c);
|
||||||
|
status = DC_STATUS_IO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
escaped = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (escaped) {
|
||||||
|
c ^= ESC_BIT;
|
||||||
|
escaped = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nbytes < size)
|
||||||
|
((unsigned char *)data)[nbytes] = c;
|
||||||
|
nbytes++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (nbytes > size) {
|
||||||
|
ERROR (hdlc->context, "HDLC frame is too large (" DC_PRINTF_SIZE " " DC_PRINTF_SIZE ").", nbytes, size);
|
||||||
|
dc_status_set_error (&status, DC_STATUS_IO);
|
||||||
|
nbytes = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actual)
|
||||||
|
*actual = nbytes;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
dc_hdlc_write (dc_iostream_t *abstract, const void *data, size_t size, size_t *actual)
|
||||||
|
{
|
||||||
|
dc_status_t status = DC_STATUS_SUCCESS;
|
||||||
|
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||||
|
size_t nbytes = 0;
|
||||||
|
|
||||||
|
// Clear the buffer.
|
||||||
|
hdlc->wbuf_offset = 0;
|
||||||
|
|
||||||
|
// Start of the packet.
|
||||||
|
hdlc->wbuf[hdlc->wbuf_offset++] = END;
|
||||||
|
|
||||||
|
// Flush the buffer if necessary.
|
||||||
|
if (hdlc->wbuf_offset >= hdlc->wbuf_size) {
|
||||||
|
status = dc_iostream_write (hdlc->iostream, hdlc->wbuf, hdlc->wbuf_offset, NULL);
|
||||||
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdlc->wbuf_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (nbytes < size) {
|
||||||
|
unsigned char c = ((const unsigned char *) data)[nbytes];
|
||||||
|
|
||||||
|
if (c == END || c == ESC) {
|
||||||
|
// Append the escape character.
|
||||||
|
hdlc->wbuf[hdlc->wbuf_offset++] = ESC;
|
||||||
|
|
||||||
|
// Flush the buffer if necessary.
|
||||||
|
if (hdlc->wbuf_offset >= hdlc->wbuf_size) {
|
||||||
|
status = dc_iostream_write (hdlc->iostream, hdlc->wbuf, hdlc->wbuf_offset, NULL);
|
||||||
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdlc->wbuf_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Escape the character.
|
||||||
|
c ^= ESC_BIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the character.
|
||||||
|
hdlc->wbuf[hdlc->wbuf_offset++] = c;
|
||||||
|
|
||||||
|
// Flush the buffer if necessary.
|
||||||
|
if (hdlc->wbuf_offset >= hdlc->wbuf_size) {
|
||||||
|
status = dc_iostream_write (hdlc->iostream, hdlc->wbuf, hdlc->wbuf_offset, NULL);
|
||||||
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdlc->wbuf_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nbytes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// End of the packet.
|
||||||
|
hdlc->wbuf[hdlc->wbuf_offset++] = END;
|
||||||
|
|
||||||
|
// Flush the buffer.
|
||||||
|
status = dc_iostream_write (hdlc->iostream, hdlc->wbuf, hdlc->wbuf_offset, NULL);
|
||||||
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdlc->wbuf_offset = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (actual)
|
||||||
|
*actual = nbytes;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
dc_hdlc_ioctl (dc_iostream_t *abstract, unsigned int request, void *data, size_t size)
|
||||||
|
{
|
||||||
|
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||||
|
|
||||||
|
return dc_iostream_ioctl (hdlc->iostream, request, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
dc_hdlc_flush (dc_iostream_t *abstract)
|
||||||
|
{
|
||||||
|
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||||
|
|
||||||
|
return dc_iostream_flush (hdlc->iostream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
dc_hdlc_purge (dc_iostream_t *abstract, dc_direction_t direction)
|
||||||
|
{
|
||||||
|
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||||
|
|
||||||
|
if (direction & DC_DIRECTION_INPUT) {
|
||||||
|
hdlc->rbuf_available = 0;
|
||||||
|
hdlc->rbuf_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dc_iostream_purge (hdlc->iostream, direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
dc_hdlc_sleep (dc_iostream_t *abstract, unsigned int milliseconds)
|
||||||
|
{
|
||||||
|
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||||
|
|
||||||
|
return dc_iostream_sleep (hdlc->iostream, milliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
dc_hdlc_close (dc_iostream_t *abstract)
|
||||||
|
{
|
||||||
|
dc_hdlc_t *hdlc = (dc_hdlc_t *) abstract;
|
||||||
|
|
||||||
|
free (hdlc->wbuf);
|
||||||
|
free (hdlc->rbuf);
|
||||||
|
|
||||||
|
return DC_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
50
src/hdlc.h
Normal file
50
src/hdlc.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* libdivecomputer
|
||||||
|
*
|
||||||
|
* Copyright (C) 2023 Jef Driesen
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DC_HDLC_H
|
||||||
|
#define DC_HDLC_H
|
||||||
|
|
||||||
|
#include <libdivecomputer/common.h>
|
||||||
|
#include <libdivecomputer/context.h>
|
||||||
|
#include <libdivecomputer/iostream.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a HDLC I/O stream layered on top of another base I/O stream.
|
||||||
|
*
|
||||||
|
* @param[out] iostream A location to store the HDLC I/O stream.
|
||||||
|
* @param[in] context A valid context.
|
||||||
|
* @param[in] base A valid I/O stream.
|
||||||
|
* @param[in] isize The input packet size in bytes.
|
||||||
|
* @param[in] osize The output packet size in bytes.
|
||||||
|
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
|
||||||
|
* on failure.
|
||||||
|
*/
|
||||||
|
dc_status_t
|
||||||
|
dc_hdlc_open (dc_iostream_t **iostream, dc_context_t *context, dc_iostream_t *base, size_t isize, size_t osize);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* DC_HDLC_H */
|
||||||
@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
#define RB_PROFILE_BEGIN 0x000000
|
#define RB_PROFILE_BEGIN 0x000000
|
||||||
#define RB_PROFILE_END 0x200000
|
#define RB_PROFILE_END 0x200000
|
||||||
#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, 0, RB_PROFILE_BEGIN, RB_PROFILE_END)
|
#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_EMPTY, RB_PROFILE_BEGIN, RB_PROFILE_END)
|
||||||
|
|
||||||
#define READY 0x4D
|
#define READY 0x4D
|
||||||
#define HEADER 0x61
|
#define HEADER 0x61
|
||||||
@ -473,11 +473,6 @@ hw_frog_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime)
|
|||||||
{
|
{
|
||||||
hw_frog_device_t *device = (hw_frog_device_t *) abstract;
|
hw_frog_device_t *device = (hw_frog_device_t *) abstract;
|
||||||
|
|
||||||
if (datetime == NULL) {
|
|
||||||
ERROR (abstract->context, "Invalid parameter specified.");
|
|
||||||
return DC_STATUS_INVALIDARGS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the command.
|
// Send the command.
|
||||||
unsigned char packet[6] = {
|
unsigned char packet[6] = {
|
||||||
datetime->hour, datetime->minute, datetime->second,
|
datetime->hour, datetime->minute, datetime->second,
|
||||||
|
|||||||
@ -31,8 +31,6 @@
|
|||||||
|
|
||||||
#define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc_device_vtable)
|
#define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc_device_vtable)
|
||||||
|
|
||||||
#define C_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
|
|
||||||
|
|
||||||
#define MAXRETRIES 9
|
#define MAXRETRIES 9
|
||||||
|
|
||||||
#define FW_190 0x015A
|
#define FW_190 0x015A
|
||||||
@ -274,6 +272,20 @@ hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
|||||||
nbytes += len;
|
nbytes += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Emit a device info event.
|
||||||
|
dc_event_devinfo_t devinfo;
|
||||||
|
devinfo.firmware = array_uint16_be (data + 264);
|
||||||
|
devinfo.serial = array_uint16_le (data + 6);
|
||||||
|
if (devinfo.serial > 7000)
|
||||||
|
devinfo.model = 3; // OSTC 2C
|
||||||
|
else if (devinfo.serial > 2048)
|
||||||
|
devinfo.model = 2; // OSTC 2N
|
||||||
|
else if (devinfo.serial > 300)
|
||||||
|
devinfo.model = 1; // OSTC Mk2
|
||||||
|
else
|
||||||
|
devinfo.model = 0; // OSTC
|
||||||
|
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,21 +303,6 @@ hw_ostc_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit a device info event.
|
|
||||||
unsigned char *data = dc_buffer_get_data (buffer);
|
|
||||||
dc_event_devinfo_t devinfo;
|
|
||||||
devinfo.firmware = array_uint16_be (data + 264);
|
|
||||||
devinfo.serial = array_uint16_le (data + 6);
|
|
||||||
if (devinfo.serial > 7000)
|
|
||||||
devinfo.model = 3; // OSTC 2C
|
|
||||||
else if (devinfo.serial > 2048)
|
|
||||||
devinfo.model = 2; // OSTC 2N
|
|
||||||
else if (devinfo.serial > 300)
|
|
||||||
devinfo.model = 1; // OSTC Mk2
|
|
||||||
else
|
|
||||||
devinfo.model = 0; // OSTC
|
|
||||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
|
||||||
|
|
||||||
rc = hw_ostc_extract_dives (abstract, dc_buffer_get_data (buffer),
|
rc = hw_ostc_extract_dives (abstract, dc_buffer_get_data (buffer),
|
||||||
dc_buffer_get_size (buffer), callback, userdata);
|
dc_buffer_get_size (buffer), callback, userdata);
|
||||||
|
|
||||||
@ -351,11 +348,6 @@ hw_ostc_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime)
|
|||||||
dc_status_t status = DC_STATUS_SUCCESS;
|
dc_status_t status = DC_STATUS_SUCCESS;
|
||||||
hw_ostc_device_t *device = (hw_ostc_device_t *) abstract;
|
hw_ostc_device_t *device = (hw_ostc_device_t *) abstract;
|
||||||
|
|
||||||
if (datetime == NULL) {
|
|
||||||
ERROR (abstract->context, "Invalid parameter specified.");
|
|
||||||
return DC_STATUS_INVALIDARGS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the command.
|
// Send the command.
|
||||||
dc_status_t rc = hw_ostc_send (device, 'b', 1);
|
dc_status_t rc = hw_ostc_send (device, 'b', 1);
|
||||||
if (rc != DC_STATUS_SUCCESS)
|
if (rc != DC_STATUS_SUCCESS)
|
||||||
|
|||||||
@ -36,7 +36,7 @@ dc_status_t
|
|||||||
hw_ostc_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
hw_ostc_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context);
|
hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
297
src/hw_ostc3.c
297
src/hw_ostc3.c
@ -30,9 +30,14 @@
|
|||||||
#include "array.h"
|
#include "array.h"
|
||||||
#include "aes.h"
|
#include "aes.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
#include "packet.h"
|
||||||
|
|
||||||
#define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc3_device_vtable)
|
#define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc3_device_vtable)
|
||||||
|
|
||||||
|
#define OSTC3FW(major,minor) ( \
|
||||||
|
(((major) & 0xFF) << 8) | \
|
||||||
|
((minor) & 0xFF))
|
||||||
|
|
||||||
#define SZ_DISPLAY 16
|
#define SZ_DISPLAY 16
|
||||||
#define SZ_CUSTOMTEXT 60
|
#define SZ_CUSTOMTEXT 60
|
||||||
#define SZ_VERSION (SZ_CUSTOMTEXT + 4)
|
#define SZ_VERSION (SZ_CUSTOMTEXT + 4)
|
||||||
@ -85,6 +90,19 @@
|
|||||||
#define NODELAY 0
|
#define NODELAY 0
|
||||||
#define TIMEOUT 400
|
#define TIMEOUT 400
|
||||||
|
|
||||||
|
#define HDR_COMPACT_LENGTH 0 // 3 bytes
|
||||||
|
#define HDR_COMPACT_SUMMARY 3 // 10 bytes
|
||||||
|
#define HDR_COMPACT_NUMBER 13 // 2 bytes
|
||||||
|
#define HDR_COMPACT_VERSION 15 // 1 byte
|
||||||
|
|
||||||
|
#define HDR_FULL_LENGTH 9 // 3 bytes
|
||||||
|
#define HDR_FULL_SUMMARY 12 // 10 bytes
|
||||||
|
#define HDR_FULL_NUMBER 80 // 2 bytes
|
||||||
|
#define HDR_FULL_VERSION 8 // 1 byte
|
||||||
|
|
||||||
|
#define HDR_FULL_POINTERS 2 // 6 bytes
|
||||||
|
#define HDR_FULL_FIRMWARE 48 // 2 bytes
|
||||||
|
|
||||||
typedef enum hw_ostc3_state_t {
|
typedef enum hw_ostc3_state_t {
|
||||||
OPEN,
|
OPEN,
|
||||||
DOWNLOAD,
|
DOWNLOAD,
|
||||||
@ -102,9 +120,6 @@ typedef struct hw_ostc3_device_t {
|
|||||||
unsigned int firmware;
|
unsigned int firmware;
|
||||||
unsigned char fingerprint[5];
|
unsigned char fingerprint[5];
|
||||||
hw_ostc3_state_t state;
|
hw_ostc3_state_t state;
|
||||||
unsigned char cache[20];
|
|
||||||
unsigned int available;
|
|
||||||
unsigned int offset;
|
|
||||||
} hw_ostc3_device_t;
|
} hw_ostc3_device_t;
|
||||||
|
|
||||||
typedef struct hw_ostc3_logbook_t {
|
typedef struct hw_ostc3_logbook_t {
|
||||||
@ -112,6 +127,7 @@ typedef struct hw_ostc3_logbook_t {
|
|||||||
unsigned int profile;
|
unsigned int profile;
|
||||||
unsigned int fingerprint;
|
unsigned int fingerprint;
|
||||||
unsigned int number;
|
unsigned int number;
|
||||||
|
unsigned int version;
|
||||||
} hw_ostc3_logbook_t;
|
} hw_ostc3_logbook_t;
|
||||||
|
|
||||||
typedef struct hw_ostc3_firmware_t {
|
typedef struct hw_ostc3_firmware_t {
|
||||||
@ -151,16 +167,18 @@ static const dc_device_vtable_t hw_ostc3_device_vtable = {
|
|||||||
|
|
||||||
static const hw_ostc3_logbook_t hw_ostc3_logbook_compact = {
|
static const hw_ostc3_logbook_t hw_ostc3_logbook_compact = {
|
||||||
RB_LOGBOOK_SIZE_COMPACT, /* size */
|
RB_LOGBOOK_SIZE_COMPACT, /* size */
|
||||||
0, /* profile */
|
HDR_COMPACT_LENGTH, /* profile */
|
||||||
3, /* fingerprint */
|
HDR_COMPACT_SUMMARY, /* fingerprint */
|
||||||
13, /* number */
|
HDR_COMPACT_NUMBER, /* number */
|
||||||
|
HDR_COMPACT_VERSION, /* version */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const hw_ostc3_logbook_t hw_ostc3_logbook_full = {
|
static const hw_ostc3_logbook_t hw_ostc3_logbook_full = {
|
||||||
RB_LOGBOOK_SIZE_FULL, /* size */
|
RB_LOGBOOK_SIZE_FULL, /* size */
|
||||||
9, /* profile */
|
HDR_FULL_LENGTH, /* profile */
|
||||||
12, /* fingerprint */
|
HDR_FULL_SUMMARY, /* fingerprint */
|
||||||
80, /* number */
|
HDR_FULL_NUMBER, /* number */
|
||||||
|
HDR_FULL_VERSION, /* version */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -187,41 +205,20 @@ static dc_status_t
|
|||||||
hw_ostc3_read (hw_ostc3_device_t *device, dc_event_progress_t *progress, unsigned char data[], size_t size)
|
hw_ostc3_read (hw_ostc3_device_t *device, dc_event_progress_t *progress, unsigned char data[], size_t size)
|
||||||
{
|
{
|
||||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||||
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
|
|
||||||
|
|
||||||
size_t nbytes = 0;
|
size_t nbytes = 0;
|
||||||
while (nbytes < size) {
|
while (nbytes < size) {
|
||||||
if (transport == DC_TRANSPORT_BLE) {
|
|
||||||
if (device->available == 0) {
|
|
||||||
// Read a packet into the cache.
|
|
||||||
size_t len = 0;
|
|
||||||
rc = dc_iostream_read (device->iostream, device->cache, sizeof(device->cache), &len);
|
|
||||||
if (rc != DC_STATUS_SUCCESS)
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
device->available = len;
|
|
||||||
device->offset = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the minimum packet size.
|
// Set the minimum packet size.
|
||||||
size_t length = (transport == DC_TRANSPORT_BLE) ? device->available : 1024;
|
size_t length = 1024;
|
||||||
|
|
||||||
// Limit the packet size to the total size.
|
// Limit the packet size to the total size.
|
||||||
if (nbytes + length > size)
|
if (nbytes + length > size)
|
||||||
length = size - nbytes;
|
length = size - nbytes;
|
||||||
|
|
||||||
if (transport == DC_TRANSPORT_BLE) {
|
// Read the packet.
|
||||||
// Copy the data from the cached packet.
|
rc = dc_iostream_read (device->iostream, data + nbytes, length, NULL);
|
||||||
memcpy (data + nbytes, device->cache + device->offset, length);
|
if (rc != DC_STATUS_SUCCESS)
|
||||||
device->available -= length;
|
return rc;
|
||||||
device->offset += length;
|
|
||||||
} else {
|
|
||||||
// Read the packet.
|
|
||||||
rc = dc_iostream_read (device->iostream, data + nbytes, length, NULL);
|
|
||||||
if (rc != DC_STATUS_SUCCESS)
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update and emit a progress event.
|
// Update and emit a progress event.
|
||||||
if (progress) {
|
if (progress) {
|
||||||
@ -239,12 +236,11 @@ static dc_status_t
|
|||||||
hw_ostc3_write (hw_ostc3_device_t *device, dc_event_progress_t *progress, const unsigned char data[], size_t size)
|
hw_ostc3_write (hw_ostc3_device_t *device, dc_event_progress_t *progress, const unsigned char data[], size_t size)
|
||||||
{
|
{
|
||||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||||
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
|
|
||||||
|
|
||||||
size_t nbytes = 0;
|
size_t nbytes = 0;
|
||||||
while (nbytes < size) {
|
while (nbytes < size) {
|
||||||
// Set the maximum packet size.
|
// Set the maximum packet size.
|
||||||
size_t length = (transport == DC_TRANSPORT_BLE) ? sizeof(device->cache) : 64;
|
size_t length = (device->hardware == OSTC4) ? 64 : 1024;
|
||||||
|
|
||||||
// Limit the packet size to the total size.
|
// Limit the packet size to the total size.
|
||||||
if (nbytes + length > size)
|
if (nbytes + length > size)
|
||||||
@ -275,10 +271,15 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
|
|||||||
unsigned int isize,
|
unsigned int isize,
|
||||||
unsigned char output[],
|
unsigned char output[],
|
||||||
unsigned int osize,
|
unsigned int osize,
|
||||||
|
unsigned int *actual,
|
||||||
unsigned int delay)
|
unsigned int delay)
|
||||||
{
|
{
|
||||||
dc_device_t *abstract = (dc_device_t *) device;
|
dc_device_t *abstract = (dc_device_t *) device;
|
||||||
dc_status_t status = DC_STATUS_SUCCESS;
|
dc_status_t status = DC_STATUS_SUCCESS;
|
||||||
|
unsigned int length = osize;
|
||||||
|
|
||||||
|
if (cmd == DIVE && length < RB_LOGBOOK_SIZE_FULL)
|
||||||
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
if (device_is_cancelled (abstract))
|
if (device_is_cancelled (abstract))
|
||||||
return DC_STATUS_CANCELLED;
|
return DC_STATUS_CANCELLED;
|
||||||
@ -288,7 +289,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
|
|||||||
|
|
||||||
// Send the command.
|
// Send the command.
|
||||||
unsigned char command[1] = {cmd};
|
unsigned char command[1] = {cmd};
|
||||||
status = hw_ostc3_write (device, NULL, command, sizeof (command));
|
status = dc_iostream_write (device->iostream, command, sizeof (command), NULL);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
ERROR (abstract->context, "Failed to send the command.");
|
ERROR (abstract->context, "Failed to send the command.");
|
||||||
return status;
|
return status;
|
||||||
@ -296,7 +297,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
|
|||||||
|
|
||||||
// Read the echo.
|
// Read the echo.
|
||||||
unsigned char echo[1] = {0};
|
unsigned char echo[1] = {0};
|
||||||
status = hw_ostc3_read (device, NULL, echo, sizeof (echo));
|
status = dc_iostream_read (device->iostream, echo, sizeof (echo), NULL);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
ERROR (abstract->context, "Failed to receive the echo.");
|
ERROR (abstract->context, "Failed to receive the echo.");
|
||||||
return status;
|
return status;
|
||||||
@ -314,31 +315,82 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (input) {
|
if (input) {
|
||||||
// Send the input data packet.
|
if (cmd == WRITE) {
|
||||||
status = hw_ostc3_write (device, progress, input, isize);
|
// Send the first byte of the input data packet.
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
status = hw_ostc3_write (device, progress, input, 1);
|
||||||
ERROR (abstract->context, "Failed to send the data packet.");
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
return status;
|
ERROR (abstract->context, "Failed to send the data packet.");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
dc_iostream_sleep (device->iostream, 10);
|
||||||
|
|
||||||
|
// Send the reamainder of the input data packet.
|
||||||
|
status = hw_ostc3_write (device, progress, input + 1, isize - 1);
|
||||||
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
|
ERROR (abstract->context, "Failed to send the data packet.");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Send the input data packet.
|
||||||
|
status = hw_ostc3_write (device, progress, input, isize);
|
||||||
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
|
ERROR (abstract->context, "Failed to send the data packet.");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output) {
|
if (output) {
|
||||||
// Read the output data packet.
|
if (cmd == DIVE) {
|
||||||
status = hw_ostc3_read (device, progress, output, osize);
|
// Read the dive header.
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
status = hw_ostc3_read (device, progress, output, RB_LOGBOOK_SIZE_FULL);
|
||||||
ERROR (abstract->context, "Failed to receive the answer.");
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
return status;
|
ERROR (abstract->context, "Failed to receive the dive header.");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the hwOS firmware detects the dive profile is no longer
|
||||||
|
// valid, it sends a modified dive header (with the begin/end
|
||||||
|
// pointer fields reset to zero, and the length field reduced to 8
|
||||||
|
// bytes), along with an empty dive profile. Detect this condition
|
||||||
|
// and adjust the expected length.
|
||||||
|
if (array_isequal (output + HDR_FULL_POINTERS, 6, 0x00) &&
|
||||||
|
array_uint24_le (output + HDR_FULL_LENGTH) == 8 &&
|
||||||
|
length > RB_LOGBOOK_SIZE_FULL + 5) {
|
||||||
|
length = RB_LOGBOOK_SIZE_FULL + 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the dive profile.
|
||||||
|
status = hw_ostc3_read (device, progress, output + RB_LOGBOOK_SIZE_FULL, length - RB_LOGBOOK_SIZE_FULL);
|
||||||
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
|
ERROR (abstract->context, "Failed to receive the dive profile.");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update and emit a progress event.
|
||||||
|
if (progress && osize > length) {
|
||||||
|
progress->current += osize - length;
|
||||||
|
device_event_emit ((dc_device_t *) device, DC_EVENT_PROGRESS, progress);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Read the output data packet.
|
||||||
|
status = hw_ostc3_read (device, progress, output, length);
|
||||||
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
|
ERROR (abstract->context, "Failed to receive the answer.");
|
||||||
|
return status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delay && device->available == 0) {
|
if (delay) {
|
||||||
dc_iostream_poll (device->iostream, delay);
|
dc_iostream_poll (device->iostream, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmd != EXIT) {
|
if (cmd != EXIT) {
|
||||||
// Read the ready byte.
|
// Read the ready byte.
|
||||||
unsigned char answer[1] = {0};
|
unsigned char answer[1] = {0};
|
||||||
status = hw_ostc3_read (device, NULL, answer, sizeof (answer));
|
status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
ERROR (abstract->context, "Failed to receive the ready byte.");
|
ERROR (abstract->context, "Failed to receive the ready byte.");
|
||||||
return status;
|
return status;
|
||||||
@ -351,6 +403,9 @@ hw_ostc3_transfer (hw_ostc3_device_t *device,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (actual)
|
||||||
|
*actual = length;
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,6 +415,7 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *i
|
|||||||
{
|
{
|
||||||
dc_status_t status = DC_STATUS_SUCCESS;
|
dc_status_t status = DC_STATUS_SUCCESS;
|
||||||
hw_ostc3_device_t *device = NULL;
|
hw_ostc3_device_t *device = NULL;
|
||||||
|
dc_transport_t transport = dc_iostream_get_transport (iostream);
|
||||||
|
|
||||||
if (out == NULL)
|
if (out == NULL)
|
||||||
return DC_STATUS_INVALIDARGS;
|
return DC_STATUS_INVALIDARGS;
|
||||||
@ -372,29 +428,36 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *i
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the default values.
|
// Set the default values.
|
||||||
device->iostream = iostream;
|
|
||||||
device->hardware = INVALID;
|
device->hardware = INVALID;
|
||||||
device->feature = 0;
|
device->feature = 0;
|
||||||
device->model = 0;
|
device->model = 0;
|
||||||
device->serial = 0;
|
device->serial = 0;
|
||||||
device->firmware = 0;
|
device->firmware = 0;
|
||||||
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
memset (device->fingerprint, 0, sizeof (device->fingerprint));
|
||||||
memset (device->cache, 0, sizeof (device->cache));
|
|
||||||
device->available = 0;
|
// Create the packet stream.
|
||||||
device->offset = 0;
|
if (transport == DC_TRANSPORT_BLE) {
|
||||||
|
status = dc_packet_open (&device->iostream, context, iostream, 244, 20);
|
||||||
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
|
ERROR (context, "Failed to create the packet stream.");
|
||||||
|
goto error_free;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
device->iostream = iostream;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the serial communication protocol (115200 8N1).
|
// Set the serial communication protocol (115200 8N1).
|
||||||
status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
|
status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
ERROR (context, "Failed to set the terminal attributes.");
|
ERROR (context, "Failed to set the terminal attributes.");
|
||||||
goto error_free;
|
goto error_free_iostream;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the timeout for receiving data (3000ms).
|
// Set the timeout for receiving data (3000ms).
|
||||||
status = dc_iostream_set_timeout (device->iostream, 3000);
|
status = dc_iostream_set_timeout (device->iostream, 3000);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
ERROR (context, "Failed to set the timeout.");
|
ERROR (context, "Failed to set the timeout.");
|
||||||
goto error_free;
|
goto error_free_iostream;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure everything is in a sane state.
|
// Make sure everything is in a sane state.
|
||||||
@ -407,6 +470,10 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *i
|
|||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
error_free_iostream:
|
||||||
|
if (transport == DC_TRANSPORT_BLE) {
|
||||||
|
dc_iostream_close (device->iostream);
|
||||||
|
}
|
||||||
error_free:
|
error_free:
|
||||||
dc_device_deallocate ((dc_device_t *) device);
|
dc_device_deallocate ((dc_device_t *) device);
|
||||||
return status;
|
return status;
|
||||||
@ -423,9 +490,9 @@ hw_ostc3_device_id (hw_ostc3_device_t *device, unsigned char data[], unsigned in
|
|||||||
|
|
||||||
// Send the command.
|
// Send the command.
|
||||||
unsigned char hardware[SZ_HARDWARE2] = {0};
|
unsigned char hardware[SZ_HARDWARE2] = {0};
|
||||||
status = hw_ostc3_transfer (device, NULL, HARDWARE2, NULL, 0, hardware, SZ_HARDWARE2, NODELAY);
|
status = hw_ostc3_transfer (device, NULL, HARDWARE2, NULL, 0, hardware, SZ_HARDWARE2, NULL, NODELAY);
|
||||||
if (status == DC_STATUS_UNSUPPORTED) {
|
if (status == DC_STATUS_UNSUPPORTED) {
|
||||||
status = hw_ostc3_transfer (device, NULL, HARDWARE, NULL, 0, hardware + 1, SZ_HARDWARE, NODELAY);
|
status = hw_ostc3_transfer (device, NULL, HARDWARE, NULL, 0, hardware + 1, SZ_HARDWARE, NULL, NODELAY);
|
||||||
}
|
}
|
||||||
if (status != DC_STATUS_SUCCESS)
|
if (status != DC_STATUS_SUCCESS)
|
||||||
return status;
|
return status;
|
||||||
@ -447,7 +514,7 @@ hw_ostc3_device_init_download (hw_ostc3_device_t *device)
|
|||||||
dc_context_t *context = (abstract ? abstract->context : NULL);
|
dc_context_t *context = (abstract ? abstract->context : NULL);
|
||||||
|
|
||||||
// Send the init command.
|
// Send the init command.
|
||||||
dc_status_t status = hw_ostc3_transfer (device, NULL, INIT, NULL, 0, NULL, 0, NODELAY);
|
dc_status_t status = hw_ostc3_transfer (device, NULL, INIT, NULL, 0, NULL, 0, NULL, NODELAY);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
ERROR (context, "Failed to send the command.");
|
ERROR (context, "Failed to send the command.");
|
||||||
return status;
|
return status;
|
||||||
@ -469,14 +536,14 @@ hw_ostc3_device_init_service (hw_ostc3_device_t *device)
|
|||||||
unsigned char answer[5] = {0};
|
unsigned char answer[5] = {0};
|
||||||
|
|
||||||
// Send the command and service key.
|
// Send the command and service key.
|
||||||
status = hw_ostc3_write (device, NULL, command, sizeof (command));
|
status = dc_iostream_write (device->iostream, command, sizeof (command), NULL);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
ERROR (abstract->context, "Failed to send the command.");
|
ERROR (abstract->context, "Failed to send the command.");
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the response.
|
// Read the response.
|
||||||
status = hw_ostc3_read (device, NULL, answer, sizeof (answer));
|
status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
ERROR (abstract->context, "Failed to receive the answer.");
|
ERROR (abstract->context, "Failed to receive the answer.");
|
||||||
return status;
|
return status;
|
||||||
@ -540,7 +607,7 @@ hw_ostc3_device_init (hw_ostc3_device_t *device, hw_ostc3_state_t state)
|
|||||||
|
|
||||||
// Read the version information.
|
// Read the version information.
|
||||||
unsigned char version[SZ_VERSION] = {0};
|
unsigned char version[SZ_VERSION] = {0};
|
||||||
rc = hw_ostc3_transfer (device, NULL, IDENTITY, NULL, 0, version, sizeof(version), NODELAY);
|
rc = hw_ostc3_transfer (device, NULL, IDENTITY, NULL, 0, version, sizeof(version), NULL, NODELAY);
|
||||||
if (rc != DC_STATUS_SUCCESS) {
|
if (rc != DC_STATUS_SUCCESS) {
|
||||||
ERROR (abstract->context, "Failed to read the version information.");
|
ERROR (abstract->context, "Failed to read the version information.");
|
||||||
return rc;
|
return rc;
|
||||||
@ -570,13 +637,22 @@ hw_ostc3_device_close (dc_device_t *abstract)
|
|||||||
|
|
||||||
// Send the exit command
|
// Send the exit command
|
||||||
if (device->state == DOWNLOAD || device->state == SERVICE) {
|
if (device->state == DOWNLOAD || device->state == SERVICE) {
|
||||||
rc = hw_ostc3_transfer (device, NULL, EXIT, NULL, 0, NULL, 0, NODELAY);
|
rc = hw_ostc3_transfer (device, NULL, EXIT, NULL, 0, NULL, 0, NULL, NODELAY);
|
||||||
if (rc != DC_STATUS_SUCCESS) {
|
if (rc != DC_STATUS_SUCCESS) {
|
||||||
ERROR (abstract->context, "Failed to send the command.");
|
ERROR (abstract->context, "Failed to send the command.");
|
||||||
dc_status_set_error(&status, rc);
|
dc_status_set_error(&status, rc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close the packet stream.
|
||||||
|
if (dc_iostream_get_transport (device->iostream) == DC_TRANSPORT_BLE) {
|
||||||
|
rc = dc_iostream_close (device->iostream);
|
||||||
|
if (rc != DC_STATUS_SUCCESS) {
|
||||||
|
ERROR (abstract->context, "Failed to close the packet stream.");
|
||||||
|
dc_status_set_error(&status, rc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,7 +690,7 @@ hw_ostc3_device_version (dc_device_t *abstract, unsigned char data[], unsigned i
|
|||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
// Send the command.
|
// Send the command.
|
||||||
rc = hw_ostc3_transfer (device, NULL, IDENTITY, NULL, 0, data, size, NODELAY);
|
rc = hw_ostc3_transfer (device, NULL, IDENTITY, NULL, 0, data, size, NULL, NODELAY);
|
||||||
if (rc != DC_STATUS_SUCCESS)
|
if (rc != DC_STATUS_SUCCESS)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -687,11 +763,11 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
|
|||||||
// This is slower, but also works for older firmware versions.
|
// This is slower, but also works for older firmware versions.
|
||||||
unsigned int compact = 1;
|
unsigned int compact = 1;
|
||||||
rc = hw_ostc3_transfer (device, &progress, COMPACT,
|
rc = hw_ostc3_transfer (device, &progress, COMPACT,
|
||||||
NULL, 0, header, RB_LOGBOOK_SIZE_COMPACT * RB_LOGBOOK_COUNT, NODELAY);
|
NULL, 0, header, RB_LOGBOOK_SIZE_COMPACT * RB_LOGBOOK_COUNT, NULL, NODELAY);
|
||||||
if (rc == DC_STATUS_UNSUPPORTED) {
|
if (rc == DC_STATUS_UNSUPPORTED) {
|
||||||
compact = 0;
|
compact = 0;
|
||||||
rc = hw_ostc3_transfer (device, &progress, HEADER,
|
rc = hw_ostc3_transfer (device, &progress, HEADER,
|
||||||
NULL, 0, header, RB_LOGBOOK_SIZE_FULL * RB_LOGBOOK_COUNT, NODELAY);
|
NULL, 0, header, RB_LOGBOOK_SIZE_FULL * RB_LOGBOOK_COUNT, NULL, NODELAY);
|
||||||
}
|
}
|
||||||
if (rc != DC_STATUS_SUCCESS) {
|
if (rc != DC_STATUS_SUCCESS) {
|
||||||
ERROR (abstract->context, "Failed to read the header.");
|
ERROR (abstract->context, "Failed to read the header.");
|
||||||
@ -747,8 +823,8 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
|
|||||||
unsigned int length = RB_LOGBOOK_SIZE_FULL + array_uint24_le (header + offset + logbook->profile) - 3;
|
unsigned int length = RB_LOGBOOK_SIZE_FULL + array_uint24_le (header + offset + logbook->profile) - 3;
|
||||||
if (!compact) {
|
if (!compact) {
|
||||||
// Workaround for a bug in older firmware versions.
|
// Workaround for a bug in older firmware versions.
|
||||||
unsigned int firmware = array_uint16_be (header + offset + 0x30);
|
unsigned int firmware = array_uint16_be (header + offset + HDR_FULL_FIRMWARE);
|
||||||
if (firmware < 93)
|
if (firmware < OSTC3FW(0,93))
|
||||||
length -= 3;
|
length -= 3;
|
||||||
}
|
}
|
||||||
if (length < RB_LOGBOOK_SIZE_FULL) {
|
if (length < RB_LOGBOOK_SIZE_FULL) {
|
||||||
@ -795,15 +871,15 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
|
|||||||
unsigned int length = RB_LOGBOOK_SIZE_FULL + array_uint24_le (header + offset + logbook->profile) - 3;
|
unsigned int length = RB_LOGBOOK_SIZE_FULL + array_uint24_le (header + offset + logbook->profile) - 3;
|
||||||
if (!compact) {
|
if (!compact) {
|
||||||
// Workaround for a bug in older firmware versions.
|
// Workaround for a bug in older firmware versions.
|
||||||
unsigned int firmware = array_uint16_be (header + offset + 0x30);
|
unsigned int firmware = array_uint16_be (header + offset + HDR_FULL_FIRMWARE);
|
||||||
if (firmware < 93)
|
if (firmware < OSTC3FW(0,93))
|
||||||
length -= 3;
|
length -= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download the dive.
|
// Download the dive.
|
||||||
unsigned char number[1] = {idx};
|
unsigned char number[1] = {idx};
|
||||||
rc = hw_ostc3_transfer (device, &progress, DIVE,
|
rc = hw_ostc3_transfer (device, &progress, DIVE,
|
||||||
number, sizeof (number), profile, length, NODELAY);
|
number, sizeof (number), profile, length, &length, NODELAY);
|
||||||
if (rc != DC_STATUS_SUCCESS) {
|
if (rc != DC_STATUS_SUCCESS) {
|
||||||
ERROR (abstract->context, "Failed to read the dive.");
|
ERROR (abstract->context, "Failed to read the dive.");
|
||||||
free (profile);
|
free (profile);
|
||||||
@ -812,11 +888,15 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify the header in the logbook and profile are identical.
|
// Verify the header in the logbook and profile are identical.
|
||||||
if (!compact && memcmp (profile, header + offset, logbook->size) != 0) {
|
if (memcmp (profile + HDR_FULL_VERSION, header + offset + logbook->version, 1) != 0 ||
|
||||||
|
compact ?
|
||||||
|
memcmp (profile + HDR_FULL_SUMMARY, header + offset + HDR_COMPACT_SUMMARY, 10) != 0 ||
|
||||||
|
memcmp (profile + HDR_FULL_NUMBER, header + offset + HDR_COMPACT_NUMBER, 2) != 0 :
|
||||||
|
memcmp (profile + HDR_FULL_SUMMARY, header + offset + HDR_FULL_SUMMARY, RB_LOGBOOK_SIZE_FULL - HDR_FULL_SUMMARY) != 0) {
|
||||||
ERROR (abstract->context, "Unexpected profile header.");
|
ERROR (abstract->context, "Unexpected profile header.");
|
||||||
free (profile);
|
free (profile);
|
||||||
free (header);
|
free (header);
|
||||||
return rc;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect invalid profile data.
|
// Detect invalid profile data.
|
||||||
@ -830,8 +910,8 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
|
|||||||
} else if (length == RB_LOGBOOK_SIZE_FULL + 2) {
|
} else if (length == RB_LOGBOOK_SIZE_FULL + 2) {
|
||||||
// A profile containing only the 2 byte end-of-profile
|
// A profile containing only the 2 byte end-of-profile
|
||||||
// marker is considered a valid empty profile.
|
// marker is considered a valid empty profile.
|
||||||
} else if (length < RB_LOGBOOK_SIZE_FULL + 5 + 2 ||
|
} else if (length < RB_LOGBOOK_SIZE_FULL + 5 ||
|
||||||
array_uint24_le (profile + RB_LOGBOOK_SIZE_FULL) + delta != array_uint24_le (profile + 9)) {
|
array_uint24_le (profile + RB_LOGBOOK_SIZE_FULL) + delta != array_uint24_le (profile + HDR_FULL_LENGTH)) {
|
||||||
// If there is more data available, then there should be a
|
// If there is more data available, then there should be a
|
||||||
// valid profile header containing a length matching the
|
// valid profile header containing a length matching the
|
||||||
// length in the dive header.
|
// length in the dive header.
|
||||||
@ -839,7 +919,7 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi
|
|||||||
length = RB_LOGBOOK_SIZE_FULL;
|
length = RB_LOGBOOK_SIZE_FULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callback && !callback (profile, length, profile + 12, sizeof (device->fingerprint), userdata))
|
if (callback && !callback (profile, length, profile + HDR_FULL_SUMMARY, sizeof (device->fingerprint), userdata))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -855,11 +935,6 @@ hw_ostc3_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime)
|
|||||||
{
|
{
|
||||||
hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract;
|
hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract;
|
||||||
|
|
||||||
if (datetime == NULL) {
|
|
||||||
ERROR (abstract->context, "Invalid parameter specified.");
|
|
||||||
return DC_STATUS_INVALIDARGS;
|
|
||||||
}
|
|
||||||
|
|
||||||
dc_status_t rc = hw_ostc3_device_init (device, DOWNLOAD);
|
dc_status_t rc = hw_ostc3_device_init (device, DOWNLOAD);
|
||||||
if (rc != DC_STATUS_SUCCESS)
|
if (rc != DC_STATUS_SUCCESS)
|
||||||
return rc;
|
return rc;
|
||||||
@ -868,7 +943,7 @@ hw_ostc3_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime)
|
|||||||
unsigned char packet[6] = {
|
unsigned char packet[6] = {
|
||||||
datetime->hour, datetime->minute, datetime->second,
|
datetime->hour, datetime->minute, datetime->second,
|
||||||
datetime->month, datetime->day, datetime->year - 2000};
|
datetime->month, datetime->day, datetime->year - 2000};
|
||||||
rc = hw_ostc3_transfer (device, NULL, CLOCK, packet, sizeof (packet), NULL, 0, NODELAY);
|
rc = hw_ostc3_transfer (device, NULL, CLOCK, packet, sizeof (packet), NULL, 0, NULL, NODELAY);
|
||||||
if (rc != DC_STATUS_SUCCESS)
|
if (rc != DC_STATUS_SUCCESS)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -896,7 +971,7 @@ hw_ostc3_device_display (dc_device_t *abstract, const char *text)
|
|||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
// Send the command.
|
// Send the command.
|
||||||
rc = hw_ostc3_transfer (device, NULL, DISPLAY, packet, sizeof (packet), NULL, 0, NODELAY);
|
rc = hw_ostc3_transfer (device, NULL, DISPLAY, packet, sizeof (packet), NULL, 0, NULL, NODELAY);
|
||||||
if (rc != DC_STATUS_SUCCESS)
|
if (rc != DC_STATUS_SUCCESS)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -924,7 +999,7 @@ hw_ostc3_device_customtext (dc_device_t *abstract, const char *text)
|
|||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
// Send the command.
|
// Send the command.
|
||||||
rc = hw_ostc3_transfer (device, NULL, CUSTOMTEXT, packet, sizeof (packet), NULL, 0, NODELAY);
|
rc = hw_ostc3_transfer (device, NULL, CUSTOMTEXT, packet, sizeof (packet), NULL, 0, NULL, NODELAY);
|
||||||
if (rc != DC_STATUS_SUCCESS)
|
if (rc != DC_STATUS_SUCCESS)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -950,7 +1025,7 @@ hw_ostc3_device_config_read (dc_device_t *abstract, unsigned int config, unsigne
|
|||||||
|
|
||||||
// Send the command.
|
// Send the command.
|
||||||
unsigned char command[1] = {config};
|
unsigned char command[1] = {config};
|
||||||
rc = hw_ostc3_transfer (device, NULL, READ, command, sizeof (command), data, size, NODELAY);
|
rc = hw_ostc3_transfer (device, NULL, READ, command, sizeof (command), data, size, NULL, NODELAY);
|
||||||
if (rc != DC_STATUS_SUCCESS)
|
if (rc != DC_STATUS_SUCCESS)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -977,7 +1052,7 @@ hw_ostc3_device_config_write (dc_device_t *abstract, unsigned int config, const
|
|||||||
// Send the command.
|
// Send the command.
|
||||||
unsigned char command[SZ_CONFIG + 1] = {config};
|
unsigned char command[SZ_CONFIG + 1] = {config};
|
||||||
memcpy(command + 1, data, size);
|
memcpy(command + 1, data, size);
|
||||||
rc = hw_ostc3_transfer (device, NULL, WRITE, command, size + 1, NULL, 0, NODELAY);
|
rc = hw_ostc3_transfer (device, NULL, WRITE, command, size + 1, NULL, 0, NULL, NODELAY);
|
||||||
if (rc != DC_STATUS_SUCCESS)
|
if (rc != DC_STATUS_SUCCESS)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -997,7 +1072,7 @@ hw_ostc3_device_config_reset (dc_device_t *abstract)
|
|||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
// Send the command.
|
// Send the command.
|
||||||
rc = hw_ostc3_transfer (device, NULL, RESET, NULL, 0, NULL, 0, NODELAY);
|
rc = hw_ostc3_transfer (device, NULL, RESET, NULL, 0, NULL, 0, NULL, NODELAY);
|
||||||
if (rc != DC_STATUS_SUCCESS)
|
if (rc != DC_STATUS_SUCCESS)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -1223,7 +1298,7 @@ hw_ostc3_firmware_erase (hw_ostc3_device_t *device, unsigned int addr, unsigned
|
|||||||
array_uint24_be_set (buffer, addr);
|
array_uint24_be_set (buffer, addr);
|
||||||
buffer[3] = blocks;
|
buffer[3] = blocks;
|
||||||
|
|
||||||
return hw_ostc3_transfer (device, NULL, S_ERASE, buffer, sizeof (buffer), NULL, 0, delay);
|
return hw_ostc3_transfer (device, NULL, S_ERASE, buffer, sizeof (buffer), NULL, 0, NULL, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
static dc_status_t
|
static dc_status_t
|
||||||
@ -1233,7 +1308,7 @@ hw_ostc3_firmware_block_read (hw_ostc3_device_t *device, unsigned int addr, unsi
|
|||||||
array_uint24_be_set (buffer, addr);
|
array_uint24_be_set (buffer, addr);
|
||||||
array_uint24_be_set (buffer + 3, block_size);
|
array_uint24_be_set (buffer + 3, block_size);
|
||||||
|
|
||||||
return hw_ostc3_transfer (device, NULL, S_BLOCK_READ, buffer, sizeof (buffer), block, block_size, NODELAY);
|
return hw_ostc3_transfer (device, NULL, S_BLOCK_READ, buffer, sizeof (buffer), block, block_size, NULL, NODELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static dc_status_t
|
static dc_status_t
|
||||||
@ -1248,7 +1323,7 @@ hw_ostc3_firmware_block_write1 (hw_ostc3_device_t *device, unsigned int addr, co
|
|||||||
array_uint24_be_set (buffer, addr);
|
array_uint24_be_set (buffer, addr);
|
||||||
memcpy (buffer + 3, block, block_size);
|
memcpy (buffer + 3, block, block_size);
|
||||||
|
|
||||||
return hw_ostc3_transfer (device, NULL, S_BLOCK_WRITE, buffer, 3 + block_size, NULL, 0, TIMEOUT);
|
return hw_ostc3_transfer (device, NULL, S_BLOCK_WRITE, buffer, 3 + block_size, NULL, 0, NULL, TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static dc_status_t
|
static dc_status_t
|
||||||
@ -1267,7 +1342,7 @@ hw_ostc3_firmware_block_write2 (hw_ostc3_device_t *device, unsigned int address,
|
|||||||
array_uint24_be_set (buffer, address);
|
array_uint24_be_set (buffer, address);
|
||||||
memcpy (buffer + 3, data + nbytes, SZ_FIRMWARE_BLOCK2);
|
memcpy (buffer + 3, data + nbytes, SZ_FIRMWARE_BLOCK2);
|
||||||
|
|
||||||
status = hw_ostc3_transfer (device, NULL, S_BLOCK_WRITE2, buffer, sizeof(buffer), NULL, 0, NODELAY);
|
status = hw_ostc3_transfer (device, NULL, S_BLOCK_WRITE2, buffer, sizeof(buffer), NULL, 0, NULL, NODELAY);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -1282,10 +1357,13 @@ hw_ostc3_firmware_block_write2 (hw_ostc3_device_t *device, unsigned int address,
|
|||||||
static dc_status_t
|
static dc_status_t
|
||||||
hw_ostc3_firmware_block_write (hw_ostc3_device_t *device, unsigned int address, const unsigned char data[], unsigned int size)
|
hw_ostc3_firmware_block_write (hw_ostc3_device_t *device, unsigned int address, const unsigned char data[], unsigned int size)
|
||||||
{
|
{
|
||||||
if (device->firmware >= 0x0309) {
|
// Support for the S_BLOCK_WRITE2 command is only available since the
|
||||||
return hw_ostc3_firmware_block_write2 (device, address, data, size);
|
// hwOS Tech firmware v3.09 and the hwOS Sport firmware v10.64.
|
||||||
} else {
|
if ((device->firmware < OSTC3FW(3,9)) ||
|
||||||
|
(device->firmware >= OSTC3FW(10,0) && device->firmware < OSTC3FW(10,64))) {
|
||||||
return hw_ostc3_firmware_block_write1 (device, address, data, size);
|
return hw_ostc3_firmware_block_write1 (device, address, data, size);
|
||||||
|
} else {
|
||||||
|
return hw_ostc3_firmware_block_write2 (device, address, data, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1305,7 +1383,7 @@ hw_ostc3_firmware_upgrade (dc_device_t *abstract, unsigned int checksum)
|
|||||||
buffer[4] = (buffer[4]<<1 | buffer[4]>>7);
|
buffer[4] = (buffer[4]<<1 | buffer[4]>>7);
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = hw_ostc3_transfer (device, NULL, S_UPGRADE, buffer, sizeof (buffer), NULL, 0, NODELAY);
|
rc = hw_ostc3_transfer (device, NULL, S_UPGRADE, buffer, sizeof (buffer), NULL, 0, NULL, NODELAY);
|
||||||
if (rc != DC_STATUS_SUCCESS) {
|
if (rc != DC_STATUS_SUCCESS) {
|
||||||
ERROR (context, "Failed to send flash firmware command");
|
ERROR (context, "Failed to send flash firmware command");
|
||||||
return rc;
|
return rc;
|
||||||
@ -1366,7 +1444,7 @@ hw_ostc3_device_fwupdate3 (dc_device_t *abstract, const char *filename)
|
|||||||
|
|
||||||
for (unsigned int len = 0; len < SZ_FIRMWARE; len += SZ_FIRMWARE_BLOCK) {
|
for (unsigned int len = 0; len < SZ_FIRMWARE; len += SZ_FIRMWARE_BLOCK) {
|
||||||
char status[SZ_DISPLAY + 1]; // Status message on the display
|
char status[SZ_DISPLAY + 1]; // Status message on the display
|
||||||
snprintf (status, sizeof(status), " Uploading %2d%%", (100 * len) / SZ_FIRMWARE);
|
dc_platform_snprintf (status, sizeof(status), " Uploading %2d%%", (100 * len) / SZ_FIRMWARE);
|
||||||
hw_ostc3_device_display (abstract, status);
|
hw_ostc3_device_display (abstract, status);
|
||||||
|
|
||||||
rc = hw_ostc3_firmware_block_write (device, FIRMWARE_AREA + len, firmware->data + len, SZ_FIRMWARE_BLOCK);
|
rc = hw_ostc3_firmware_block_write (device, FIRMWARE_AREA + len, firmware->data + len, SZ_FIRMWARE_BLOCK);
|
||||||
@ -1385,7 +1463,7 @@ hw_ostc3_device_fwupdate3 (dc_device_t *abstract, const char *filename)
|
|||||||
for (unsigned int len = 0; len < SZ_FIRMWARE; len += SZ_FIRMWARE_BLOCK) {
|
for (unsigned int len = 0; len < SZ_FIRMWARE; len += SZ_FIRMWARE_BLOCK) {
|
||||||
unsigned char block[SZ_FIRMWARE_BLOCK];
|
unsigned char block[SZ_FIRMWARE_BLOCK];
|
||||||
char status[SZ_DISPLAY + 1]; // Status message on the display
|
char status[SZ_DISPLAY + 1]; // Status message on the display
|
||||||
snprintf (status, sizeof(status), " Verifying %2d%%", (100 * len) / SZ_FIRMWARE);
|
dc_platform_snprintf (status, sizeof(status), " Verifying %2d%%", (100 * len) / SZ_FIRMWARE);
|
||||||
hw_ostc3_device_display (abstract, status);
|
hw_ostc3_device_display (abstract, status);
|
||||||
|
|
||||||
rc = hw_ostc3_firmware_block_read (device, FIRMWARE_AREA + len, block, sizeof (block));
|
rc = hw_ostc3_firmware_block_read (device, FIRMWARE_AREA + len, block, sizeof (block));
|
||||||
@ -1487,7 +1565,7 @@ hw_ostc3_device_fwupdate4 (dc_device_t *abstract, const char *filename)
|
|||||||
// Read the firmware version info.
|
// Read the firmware version info.
|
||||||
unsigned char fwinfo[SZ_FWINFO] = {0};
|
unsigned char fwinfo[SZ_FWINFO] = {0};
|
||||||
status = hw_ostc3_transfer (device, NULL, S_FWINFO,
|
status = hw_ostc3_transfer (device, NULL, S_FWINFO,
|
||||||
data + offset + 4, 1, fwinfo, sizeof(fwinfo), NODELAY);
|
data + offset + 4, 1, fwinfo, sizeof(fwinfo), NULL, NODELAY);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
ERROR (abstract->context, "Failed to read the firmware info.");
|
ERROR (abstract->context, "Failed to read the firmware info.");
|
||||||
goto error;
|
goto error;
|
||||||
@ -1500,7 +1578,7 @@ hw_ostc3_device_fwupdate4 (dc_device_t *abstract, const char *filename)
|
|||||||
!array_isequal(fwinfo, sizeof(fwinfo), 0xFF))
|
!array_isequal(fwinfo, sizeof(fwinfo), 0xFF))
|
||||||
{
|
{
|
||||||
status = hw_ostc3_transfer (device, &progress, S_UPLOAD,
|
status = hw_ostc3_transfer (device, &progress, S_UPLOAD,
|
||||||
data + offset, length, NULL, 0, usecs / 1000);
|
data + offset, length, NULL, 0, NULL, usecs / 1000);
|
||||||
if (status != DC_STATUS_SUCCESS) {
|
if (status != DC_STATUS_SUCCESS) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -1637,6 +1715,25 @@ hw_ostc3_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (device->hardware == OSTC4) {
|
||||||
|
return DC_STATUS_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit a device info event.
|
||||||
|
dc_event_devinfo_t devinfo;
|
||||||
|
devinfo.firmware = device->firmware;
|
||||||
|
devinfo.serial = device->serial;
|
||||||
|
if (device->hardware != UNKNOWN) {
|
||||||
|
devinfo.model = device->hardware;
|
||||||
|
} else {
|
||||||
|
// Fallback to the serial number.
|
||||||
|
if (devinfo.serial > 10000)
|
||||||
|
devinfo.model = SPORT;
|
||||||
|
else
|
||||||
|
devinfo.model = OSTC3;
|
||||||
|
}
|
||||||
|
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||||
|
|
||||||
// Allocate the required amount of memory.
|
// Allocate the required amount of memory.
|
||||||
if (!dc_buffer_resize (buffer, SZ_MEMORY)) {
|
if (!dc_buffer_resize (buffer, SZ_MEMORY)) {
|
||||||
ERROR (abstract->context, "Insufficient buffer space available.");
|
ERROR (abstract->context, "Insufficient buffer space available.");
|
||||||
|
|||||||
@ -36,7 +36,7 @@ dc_status_t
|
|||||||
hw_ostc3_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
hw_ostc3_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model);
|
hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "libdivecomputer/units.h"
|
#include "libdivecomputer/units.h"
|
||||||
|
|
||||||
@ -36,10 +37,6 @@
|
|||||||
|
|
||||||
#define UNDEFINED 0xFFFFFFFF
|
#define UNDEFINED 0xFFFFFFFF
|
||||||
|
|
||||||
#define ALL 0
|
|
||||||
#define FIXED 1
|
|
||||||
#define MANUAL 2
|
|
||||||
|
|
||||||
#define HEADER 1
|
#define HEADER 1
|
||||||
#define PROFILE 2
|
#define PROFILE 2
|
||||||
|
|
||||||
@ -69,6 +66,10 @@
|
|||||||
#define OSTC3_APNEA 3
|
#define OSTC3_APNEA 3
|
||||||
#define OSTC3_PSCR 4
|
#define OSTC3_PSCR 4
|
||||||
|
|
||||||
|
#define OSTC3_ZHL16 0
|
||||||
|
#define OSTC3_ZHL16_GF 1
|
||||||
|
#define OSTC4_VPM 2
|
||||||
|
|
||||||
#define OSTC4 0x3B
|
#define OSTC4 0x3B
|
||||||
|
|
||||||
#define OSTC3FW(major,minor) ( \
|
#define OSTC3FW(major,minor) ( \
|
||||||
@ -90,18 +91,26 @@ typedef struct hw_ostc_sample_info_t {
|
|||||||
typedef struct hw_ostc_layout_t {
|
typedef struct hw_ostc_layout_t {
|
||||||
unsigned int datetime;
|
unsigned int datetime;
|
||||||
unsigned int maxdepth;
|
unsigned int maxdepth;
|
||||||
unsigned int avgdepth;
|
|
||||||
unsigned int divetime;
|
unsigned int divetime;
|
||||||
unsigned int atmospheric;
|
|
||||||
unsigned int salinity;
|
|
||||||
unsigned int duration;
|
|
||||||
unsigned int temperature;
|
unsigned int temperature;
|
||||||
|
unsigned int atmospheric;
|
||||||
unsigned int firmware;
|
unsigned int firmware;
|
||||||
|
unsigned int salinity;
|
||||||
|
unsigned int avgdepth;
|
||||||
|
unsigned int duration;
|
||||||
|
unsigned int gf;
|
||||||
|
unsigned int decomodel;
|
||||||
|
unsigned int divemode;
|
||||||
} hw_ostc_layout_t;
|
} hw_ostc_layout_t;
|
||||||
|
|
||||||
typedef struct hw_ostc_gasmix_t {
|
typedef struct hw_ostc_gasmix_t {
|
||||||
|
unsigned int id;
|
||||||
unsigned int oxygen;
|
unsigned int oxygen;
|
||||||
unsigned int helium;
|
unsigned int helium;
|
||||||
|
unsigned int type;
|
||||||
|
unsigned int enabled;
|
||||||
|
unsigned int active;
|
||||||
|
unsigned int diluent;
|
||||||
} hw_ostc_gasmix_t;
|
} hw_ostc_gasmix_t;
|
||||||
|
|
||||||
typedef struct hw_ostc_parser_t {
|
typedef struct hw_ostc_parser_t {
|
||||||
@ -115,21 +124,25 @@ typedef struct hw_ostc_parser_t {
|
|||||||
const hw_ostc_layout_t *layout;
|
const hw_ostc_layout_t *layout;
|
||||||
unsigned int ngasmixes;
|
unsigned int ngasmixes;
|
||||||
unsigned int nfixed;
|
unsigned int nfixed;
|
||||||
|
unsigned int ndisabled;
|
||||||
unsigned int initial;
|
unsigned int initial;
|
||||||
unsigned int initial_setpoint;
|
unsigned int initial_setpoint;
|
||||||
unsigned int initial_cns;
|
unsigned int initial_cns;
|
||||||
hw_ostc_gasmix_t gasmix[NGASMIXES];
|
hw_ostc_gasmix_t gasmix[NGASMIXES];
|
||||||
} hw_ostc_parser_t;
|
} hw_ostc_parser_t;
|
||||||
|
|
||||||
static dc_status_t hw_ostc_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
|
||||||
static dc_status_t hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
static dc_status_t hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||||
static dc_status_t hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
static dc_status_t hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||||
static dc_status_t hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
static dc_status_t hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||||
|
|
||||||
|
static dc_status_t hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t callback, void *userdata);
|
||||||
|
|
||||||
static const dc_parser_vtable_t hw_ostc_parser_vtable = {
|
static const dc_parser_vtable_t hw_ostc_parser_vtable = {
|
||||||
sizeof(hw_ostc_parser_t),
|
sizeof(hw_ostc_parser_t),
|
||||||
DC_FAMILY_HW_OSTC,
|
DC_FAMILY_HW_OSTC,
|
||||||
hw_ostc_parser_set_data, /* set_data */
|
NULL, /* set_clock */
|
||||||
|
NULL, /* set_atmospheric */
|
||||||
|
NULL, /* set_density */
|
||||||
hw_ostc_parser_get_datetime, /* datetime */
|
hw_ostc_parser_get_datetime, /* datetime */
|
||||||
hw_ostc_parser_get_field, /* fields */
|
hw_ostc_parser_get_field, /* fields */
|
||||||
hw_ostc_parser_samples_foreach, /* samples_foreach */
|
hw_ostc_parser_samples_foreach, /* samples_foreach */
|
||||||
@ -139,53 +152,57 @@ static const dc_parser_vtable_t hw_ostc_parser_vtable = {
|
|||||||
static const hw_ostc_layout_t hw_ostc_layout_ostc = {
|
static const hw_ostc_layout_t hw_ostc_layout_ostc = {
|
||||||
3, /* datetime */
|
3, /* datetime */
|
||||||
8, /* maxdepth */
|
8, /* maxdepth */
|
||||||
45, /* avgdepth */
|
|
||||||
10, /* divetime */
|
10, /* divetime */
|
||||||
15, /* atmospheric */
|
|
||||||
43, /* salinity */
|
|
||||||
47, /* duration */
|
|
||||||
13, /* temperature */
|
13, /* temperature */
|
||||||
|
15, /* atmospheric */
|
||||||
32, /* firmware */
|
32, /* firmware */
|
||||||
|
43, /* salinity */
|
||||||
|
45, /* avgdepth */
|
||||||
|
47, /* duration */
|
||||||
|
49, /* gf */
|
||||||
|
UNDEFINED, /* decomodel */
|
||||||
|
51, /* divemode */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const hw_ostc_layout_t hw_ostc_layout_frog = {
|
static const hw_ostc_layout_t hw_ostc_layout_frog = {
|
||||||
9, /* datetime */
|
9, /* datetime */
|
||||||
14, /* maxdepth */
|
14, /* maxdepth */
|
||||||
45, /* avgdepth */
|
|
||||||
16, /* divetime */
|
16, /* divetime */
|
||||||
21, /* atmospheric */
|
|
||||||
43, /* salinity */
|
|
||||||
47, /* duration */
|
|
||||||
19, /* temperature */
|
19, /* temperature */
|
||||||
|
21, /* atmospheric */
|
||||||
32, /* firmware */
|
32, /* firmware */
|
||||||
|
43, /* salinity */
|
||||||
|
45, /* avgdepth */
|
||||||
|
47, /* duration */
|
||||||
|
49, /* gf */
|
||||||
|
UNDEFINED, /* decomodel */
|
||||||
|
51, /* divemode */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const hw_ostc_layout_t hw_ostc_layout_ostc3 = {
|
static const hw_ostc_layout_t hw_ostc_layout_ostc3 = {
|
||||||
12, /* datetime */
|
12, /* datetime */
|
||||||
17, /* maxdepth */
|
17, /* maxdepth */
|
||||||
73, /* avgdepth */
|
|
||||||
19, /* divetime */
|
19, /* divetime */
|
||||||
24, /* atmospheric */
|
|
||||||
70, /* salinity */
|
|
||||||
75, /* duration */
|
|
||||||
22, /* temperature */
|
22, /* temperature */
|
||||||
|
24, /* atmospheric */
|
||||||
48, /* firmware */
|
48, /* firmware */
|
||||||
|
70, /* salinity */
|
||||||
|
73, /* avgdepth */
|
||||||
|
75, /* duration */
|
||||||
|
77, /* gf */
|
||||||
|
79, /* decomodel */
|
||||||
|
82, /* divemode */
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
hw_ostc_find_gasmix (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he, unsigned int type)
|
hw_ostc_find_gasmix_manual (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he, unsigned int dil)
|
||||||
{
|
{
|
||||||
unsigned int offset = 0;
|
unsigned int offset = parser->nfixed - parser->ndisabled;
|
||||||
unsigned int count = parser->ngasmixes;
|
unsigned int count = parser->ngasmixes;
|
||||||
if (type == FIXED) {
|
|
||||||
count = parser->nfixed;
|
|
||||||
} else if (type == MANUAL) {
|
|
||||||
offset = parser->nfixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int i = offset;
|
unsigned int i = offset;
|
||||||
while (i < count) {
|
while (i < count) {
|
||||||
if (o2 == parser->gasmix[i].oxygen && he == parser->gasmix[i].helium)
|
if (o2 == parser->gasmix[i].oxygen && he == parser->gasmix[i].helium && dil == parser->gasmix[i].diluent)
|
||||||
break;
|
break;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@ -193,6 +210,34 @@ hw_ostc_find_gasmix (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he,
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
hw_ostc_find_gasmix_fixed (hw_ostc_parser_t *parser, unsigned int id)
|
||||||
|
{
|
||||||
|
unsigned int offset = 0;
|
||||||
|
unsigned int count = parser->nfixed - parser->ndisabled;
|
||||||
|
|
||||||
|
unsigned int i = offset;
|
||||||
|
while (i < count) {
|
||||||
|
if (id == parser->gasmix[i].id)
|
||||||
|
break;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
hw_ostc_is_ccr (unsigned int divemode, unsigned int version)
|
||||||
|
{
|
||||||
|
if (version == 0x21) {
|
||||||
|
return divemode == OSTC_ZHL16_CC || divemode == OSTC_ZHL16_CC_GF || divemode == OSTC_PSCR_GF;
|
||||||
|
} else if (version == 0x23 || version == 0x24) {
|
||||||
|
return divemode == OSTC3_CC || divemode == OSTC3_PSCR;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static dc_status_t
|
static dc_status_t
|
||||||
hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
||||||
{
|
{
|
||||||
@ -241,6 +286,13 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
|||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the dive mode.
|
||||||
|
unsigned int divemode = layout->divemode < header ?
|
||||||
|
data[layout->divemode] : UNDEFINED;
|
||||||
|
|
||||||
|
// Get the CCR mode.
|
||||||
|
unsigned int ccr = hw_ostc_is_ccr (divemode, version);
|
||||||
|
|
||||||
// Get all the gas mixes, the index of the inital mix,
|
// Get all the gas mixes, the index of the inital mix,
|
||||||
// the initial setpoint (used in the fixed setpoint CCR mode),
|
// the initial setpoint (used in the fixed setpoint CCR mode),
|
||||||
// and the initial CNS from the header
|
// and the initial CNS from the header
|
||||||
@ -255,21 +307,31 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
|||||||
initial = data[31];
|
initial = data[31];
|
||||||
}
|
}
|
||||||
for (unsigned int i = 0; i < ngasmixes; ++i) {
|
for (unsigned int i = 0; i < ngasmixes; ++i) {
|
||||||
|
gasmix[i].id = i + 1;
|
||||||
gasmix[i].oxygen = data[25 + 2 * i];
|
gasmix[i].oxygen = data[25 + 2 * i];
|
||||||
gasmix[i].helium = 0;
|
gasmix[i].helium = 0;
|
||||||
|
gasmix[i].type = 0;
|
||||||
|
gasmix[i].enabled = 1;
|
||||||
|
gasmix[i].active = 0;
|
||||||
|
gasmix[i].diluent = 0;
|
||||||
}
|
}
|
||||||
} else if (version == 0x23 || version == 0x24) {
|
} else if (version == 0x23 || version == 0x24) {
|
||||||
ngasmixes = 5;
|
ngasmixes = 5;
|
||||||
for (unsigned int i = 0; i < ngasmixes; ++i) {
|
for (unsigned int i = 0; i < ngasmixes; ++i) {
|
||||||
|
gasmix[i].id = i + 1;
|
||||||
gasmix[i].oxygen = data[28 + 4 * i + 0];
|
gasmix[i].oxygen = data[28 + 4 * i + 0];
|
||||||
gasmix[i].helium = data[28 + 4 * i + 1];
|
gasmix[i].helium = data[28 + 4 * i + 1];
|
||||||
|
gasmix[i].type = data[28 + 4 * i + 3];
|
||||||
|
gasmix[i].enabled = gasmix[i].type != 0;
|
||||||
|
gasmix[i].active = 0;
|
||||||
|
gasmix[i].diluent = ccr;
|
||||||
// Find the first gas marked as the initial gas.
|
// Find the first gas marked as the initial gas.
|
||||||
if (initial == UNDEFINED && data[28 + 4 * i + 3] == 1) {
|
if (initial == UNDEFINED && data[28 + 4 * i + 3] == 1) {
|
||||||
initial = i + 1; /* One based index! */
|
initial = i + 1; /* One based index! */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The first fixed setpoint is the initial setpoint in CCR mode.
|
// The first fixed setpoint is the initial setpoint in CCR mode.
|
||||||
if (data[82] == OSTC3_CC) {
|
if (ccr) {
|
||||||
initial_setpoint = data[60];
|
initial_setpoint = data[60];
|
||||||
}
|
}
|
||||||
// Initial CNS
|
// Initial CNS
|
||||||
@ -280,8 +342,17 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
|||||||
initial = data[31];
|
initial = data[31];
|
||||||
}
|
}
|
||||||
for (unsigned int i = 0; i < ngasmixes; ++i) {
|
for (unsigned int i = 0; i < ngasmixes; ++i) {
|
||||||
|
gasmix[i].id = i + 1;
|
||||||
gasmix[i].oxygen = data[19 + 2 * i + 0];
|
gasmix[i].oxygen = data[19 + 2 * i + 0];
|
||||||
gasmix[i].helium = data[19 + 2 * i + 1];
|
gasmix[i].helium = data[19 + 2 * i + 1];
|
||||||
|
gasmix[i].type = 0;
|
||||||
|
if (version == 0x21) {
|
||||||
|
gasmix[i].enabled = data[53] & (1 << i);
|
||||||
|
} else {
|
||||||
|
gasmix[i].enabled = 1;
|
||||||
|
}
|
||||||
|
gasmix[i].active = 0;
|
||||||
|
gasmix[i].diluent = ccr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (initial != UNDEFINED) {
|
if (initial != UNDEFINED) {
|
||||||
@ -289,7 +360,6 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
|||||||
ERROR(abstract->context, "Invalid initial gas mix.");
|
ERROR(abstract->context, "Invalid initial gas mix.");
|
||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
initial--; /* Convert to a zero based index. */
|
|
||||||
} else {
|
} else {
|
||||||
WARNING(abstract->context, "No initial gas mix available.");
|
WARNING(abstract->context, "No initial gas mix available.");
|
||||||
}
|
}
|
||||||
@ -300,6 +370,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
|||||||
parser->layout = layout;
|
parser->layout = layout;
|
||||||
parser->ngasmixes = ngasmixes;
|
parser->ngasmixes = ngasmixes;
|
||||||
parser->nfixed = ngasmixes;
|
parser->nfixed = ngasmixes;
|
||||||
|
parser->ndisabled = 0;
|
||||||
parser->initial = initial;
|
parser->initial = initial;
|
||||||
parser->initial_setpoint = initial_setpoint;
|
parser->initial_setpoint = initial_setpoint;
|
||||||
parser->initial_cns = initial_cns;
|
parser->initial_cns = initial_cns;
|
||||||
@ -312,7 +383,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static dc_status_t
|
static dc_status_t
|
||||||
hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsigned int hwos, unsigned int model)
|
hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int hwos, unsigned int model)
|
||||||
{
|
{
|
||||||
hw_ostc_parser_t *parser = NULL;
|
hw_ostc_parser_t *parser = NULL;
|
||||||
|
|
||||||
@ -320,7 +391,7 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign
|
|||||||
return DC_STATUS_INVALIDARGS;
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
// Allocate memory.
|
// Allocate memory.
|
||||||
parser = (hw_ostc_parser_t *) dc_parser_allocate (context, &hw_ostc_parser_vtable);
|
parser = (hw_ostc_parser_t *) dc_parser_allocate (context, &hw_ostc_parser_vtable, data, size);
|
||||||
if (parser == NULL) {
|
if (parser == NULL) {
|
||||||
ERROR (context, "Failed to allocate memory.");
|
ERROR (context, "Failed to allocate memory.");
|
||||||
return DC_STATUS_NOMEMORY;
|
return DC_STATUS_NOMEMORY;
|
||||||
@ -335,12 +406,18 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign
|
|||||||
parser->layout = NULL;
|
parser->layout = NULL;
|
||||||
parser->ngasmixes = 0;
|
parser->ngasmixes = 0;
|
||||||
parser->nfixed = 0;
|
parser->nfixed = 0;
|
||||||
|
parser->ndisabled = 0;
|
||||||
parser->initial = 0;
|
parser->initial = 0;
|
||||||
parser->initial_setpoint = 0;
|
parser->initial_setpoint = 0;
|
||||||
parser->initial_cns = 0;
|
parser->initial_cns = 0;
|
||||||
for (unsigned int i = 0; i < NGASMIXES; ++i) {
|
for (unsigned int i = 0; i < NGASMIXES; ++i) {
|
||||||
|
parser->gasmix[i].id = 0;
|
||||||
parser->gasmix[i].oxygen = 0;
|
parser->gasmix[i].oxygen = 0;
|
||||||
parser->gasmix[i].helium = 0;
|
parser->gasmix[i].helium = 0;
|
||||||
|
parser->gasmix[i].type = 0;
|
||||||
|
parser->gasmix[i].enabled = 0;
|
||||||
|
parser->gasmix[i].active = 0;
|
||||||
|
parser->gasmix[i].diluent = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = (dc_parser_t *) parser;
|
*out = (dc_parser_t *) parser;
|
||||||
@ -350,41 +427,17 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign
|
|||||||
|
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context)
|
hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||||
{
|
{
|
||||||
return hw_ostc_parser_create_internal (out, context, 0, 0);
|
return hw_ostc_parser_create_internal (out, context, data, size, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
dc_status_t
|
dc_status_t
|
||||||
hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||||
{
|
{
|
||||||
return hw_ostc_parser_create_internal (out, context, 1, model);
|
return hw_ostc_parser_create_internal (out, context, data, size, 1, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
static dc_status_t
|
|
||||||
hw_ostc_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
|
||||||
{
|
|
||||||
hw_ostc_parser_t *parser = (hw_ostc_parser_t *) abstract;
|
|
||||||
|
|
||||||
// Reset the cache.
|
|
||||||
parser->cached = 0;
|
|
||||||
parser->version = 0;
|
|
||||||
parser->header = 0;
|
|
||||||
parser->layout = NULL;
|
|
||||||
parser->ngasmixes = 0;
|
|
||||||
parser->nfixed = 0;
|
|
||||||
parser->initial = 0;
|
|
||||||
parser->initial_setpoint = 0;
|
|
||||||
parser->initial_cns = 0;
|
|
||||||
for (unsigned int i = 0; i < NGASMIXES; ++i) {
|
|
||||||
parser->gasmix[i].oxygen = 0;
|
|
||||||
parser->gasmix[i].helium = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static dc_status_t
|
static dc_status_t
|
||||||
hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||||
{
|
{
|
||||||
@ -458,7 +511,7 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
|||||||
|
|
||||||
// Cache the profile data.
|
// Cache the profile data.
|
||||||
if (parser->cached < PROFILE) {
|
if (parser->cached < PROFILE) {
|
||||||
rc = hw_ostc_parser_samples_foreach (abstract, NULL, NULL);
|
rc = hw_ostc_parser_internal_foreach (parser, NULL, NULL);
|
||||||
if (rc != DC_STATUS_SUCCESS)
|
if (rc != DC_STATUS_SUCCESS)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -468,6 +521,8 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
|||||||
|
|
||||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||||
dc_salinity_t *water = (dc_salinity_t *) value;
|
dc_salinity_t *water = (dc_salinity_t *) value;
|
||||||
|
dc_decomodel_t *decomodel = (dc_decomodel_t *) value;
|
||||||
|
|
||||||
unsigned int salinity = data[layout->salinity];
|
unsigned int salinity = data[layout->salinity];
|
||||||
if (version == 0x23 || version == 0x24)
|
if (version == 0x23 || version == 0x24)
|
||||||
salinity += 100;
|
salinity += 100;
|
||||||
@ -489,6 +544,8 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
|||||||
*((unsigned int *) value) = parser->ngasmixes;
|
*((unsigned int *) value) = parser->ngasmixes;
|
||||||
break;
|
break;
|
||||||
case DC_FIELD_GASMIX:
|
case DC_FIELD_GASMIX:
|
||||||
|
gasmix->usage = parser->gasmix[flags].diluent ?
|
||||||
|
DC_USAGE_DILUENT : DC_USAGE_NONE;
|
||||||
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
|
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
|
||||||
gasmix->helium = parser->gasmix[flags].helium / 100.0;
|
gasmix->helium = parser->gasmix[flags].helium / 100.0;
|
||||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||||
@ -511,7 +568,7 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
|||||||
break;
|
break;
|
||||||
case DC_FIELD_DIVEMODE:
|
case DC_FIELD_DIVEMODE:
|
||||||
if (version == 0x21) {
|
if (version == 0x21) {
|
||||||
switch (data[51]) {
|
switch (data[layout->divemode]) {
|
||||||
case OSTC_APNEA:
|
case OSTC_APNEA:
|
||||||
*((dc_divemode_t *) value) = DC_DIVEMODE_FREEDIVE;
|
*((dc_divemode_t *) value) = DC_DIVEMODE_FREEDIVE;
|
||||||
break;
|
break;
|
||||||
@ -533,7 +590,7 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
|||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
} else if (version == 0x22) {
|
} else if (version == 0x22) {
|
||||||
switch (data[51]) {
|
switch (data[layout->divemode]) {
|
||||||
case FROG_ZHL16:
|
case FROG_ZHL16:
|
||||||
case FROG_ZHL16_GF:
|
case FROG_ZHL16_GF:
|
||||||
*((dc_divemode_t *) value) = DC_DIVEMODE_OC;
|
*((dc_divemode_t *) value) = DC_DIVEMODE_OC;
|
||||||
@ -545,7 +602,7 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
|||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
} else if (version == 0x23 || version == 0x24) {
|
} else if (version == 0x23 || version == 0x24) {
|
||||||
switch (data[82]) {
|
switch (data[layout->divemode]) {
|
||||||
case OSTC3_OC:
|
case OSTC3_OC:
|
||||||
*((dc_divemode_t *) value) = DC_DIVEMODE_OC;
|
*((dc_divemode_t *) value) = DC_DIVEMODE_OC;
|
||||||
break;
|
break;
|
||||||
@ -568,6 +625,70 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
|||||||
return DC_STATUS_UNSUPPORTED;
|
return DC_STATUS_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DC_FIELD_DECOMODEL:
|
||||||
|
if (version == 0x21) {
|
||||||
|
switch (data[layout->divemode]) {
|
||||||
|
case OSTC_APNEA:
|
||||||
|
case OSTC_GAUGE:
|
||||||
|
decomodel->type = DC_DECOMODEL_NONE;
|
||||||
|
break;
|
||||||
|
case OSTC_ZHL16_OC:
|
||||||
|
case OSTC_ZHL16_CC:
|
||||||
|
decomodel->type = DC_DECOMODEL_BUHLMANN;
|
||||||
|
decomodel->params.gf.low = 100;
|
||||||
|
decomodel->params.gf.high = 100;
|
||||||
|
break;
|
||||||
|
case OSTC_ZHL16_OC_GF:
|
||||||
|
case OSTC_ZHL16_CC_GF:
|
||||||
|
case OSTC_PSCR_GF:
|
||||||
|
decomodel->type = DC_DECOMODEL_BUHLMANN;
|
||||||
|
decomodel->params.gf.low = data[layout->gf + 0];
|
||||||
|
decomodel->params.gf.high = data[layout->gf + 1];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
}
|
||||||
|
} else if (version == 0x22) {
|
||||||
|
switch (data[layout->divemode]) {
|
||||||
|
case FROG_ZHL16:
|
||||||
|
decomodel->type = DC_DECOMODEL_BUHLMANN;
|
||||||
|
decomodel->params.gf.low = 100;
|
||||||
|
decomodel->params.gf.high = 100;
|
||||||
|
break;
|
||||||
|
case FROG_ZHL16_GF:
|
||||||
|
decomodel->type = DC_DECOMODEL_BUHLMANN;
|
||||||
|
decomodel->params.gf.low = data[layout->gf + 0];
|
||||||
|
decomodel->params.gf.high = data[layout->gf + 1];
|
||||||
|
break;
|
||||||
|
case FROG_APNEA:
|
||||||
|
decomodel->type = DC_DECOMODEL_NONE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
}
|
||||||
|
} else if (version == 0x23 || version == 0x24) {
|
||||||
|
switch (data[layout->decomodel]) {
|
||||||
|
case OSTC3_ZHL16:
|
||||||
|
decomodel->type = DC_DECOMODEL_BUHLMANN;
|
||||||
|
decomodel->params.gf.low = 100;
|
||||||
|
decomodel->params.gf.high = 100;
|
||||||
|
break;
|
||||||
|
case OSTC3_ZHL16_GF:
|
||||||
|
decomodel->type = DC_DECOMODEL_BUHLMANN;
|
||||||
|
decomodel->params.gf.low = data[layout->gf + 0];
|
||||||
|
decomodel->params.gf.high = data[layout->gf + 1];
|
||||||
|
break;
|
||||||
|
case OSTC4_VPM:
|
||||||
|
decomodel->type = DC_DECOMODEL_VPM;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return DC_STATUS_DATAFORMAT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return DC_STATUS_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
decomodel->conservatism = 0;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return DC_STATUS_UNSUPPORTED;
|
return DC_STATUS_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
@ -578,24 +699,21 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
|||||||
|
|
||||||
|
|
||||||
static dc_status_t
|
static dc_status_t
|
||||||
hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t callback, void *userdata)
|
||||||
{
|
{
|
||||||
hw_ostc_parser_t *parser = (hw_ostc_parser_t *) abstract;
|
dc_parser_t *abstract = (dc_parser_t *) parser;
|
||||||
const unsigned char *data = abstract->data;
|
const unsigned char *data = abstract->data;
|
||||||
unsigned int size = abstract->size;
|
unsigned int size = abstract->size;
|
||||||
|
|
||||||
// Cache the parser data.
|
|
||||||
dc_status_t rc = hw_ostc_parser_cache (parser);
|
|
||||||
if (rc != DC_STATUS_SUCCESS)
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
unsigned int version = parser->version;
|
unsigned int version = parser->version;
|
||||||
unsigned int header = parser->header;
|
unsigned int header = parser->header;
|
||||||
const hw_ostc_layout_t *layout = parser->layout;
|
const hw_ostc_layout_t *layout = parser->layout;
|
||||||
|
|
||||||
// Exit if no profile data available.
|
// Exit if no profile data available.
|
||||||
if (size == header || (size == header + 2 &&
|
const unsigned char empty[] = {0x08, 0x00, 0x00, 0xFD, 0xFD};
|
||||||
data[header] == 0xFD && data[header + 1] == 0xFD)) {
|
if (size == header ||
|
||||||
|
(size == header + 2 && memcmp(data + header, empty + 3, 2) == 0) ||
|
||||||
|
(size == header + 5 && memcmp(data + header, empty, 5) == 0)) {
|
||||||
parser->cached = PROFILE;
|
parser->cached = PROFILE;
|
||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -683,9 +801,16 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
|||||||
firmware = array_uint16_be (data + layout->firmware);
|
firmware = array_uint16_be (data + layout->firmware);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the dive mode.
|
||||||
|
unsigned int divemode = layout->divemode < header ?
|
||||||
|
data[layout->divemode] : UNDEFINED;
|
||||||
|
|
||||||
|
// Get the CCR mode.
|
||||||
|
unsigned int ccr = hw_ostc_is_ccr (divemode, version);
|
||||||
|
|
||||||
unsigned int time = 0;
|
unsigned int time = 0;
|
||||||
unsigned int nsamples = 0;
|
unsigned int nsamples = 0;
|
||||||
unsigned int tank = parser->initial != UNDEFINED ? parser->initial : 0;
|
unsigned int tank = parser->initial != UNDEFINED ? parser->initial - 1 : 0;
|
||||||
|
|
||||||
unsigned int offset = header;
|
unsigned int offset = header;
|
||||||
if (version == 0x23 || version == 0x24)
|
if (version == 0x23 || version == 0x24)
|
||||||
@ -697,31 +822,33 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
|||||||
|
|
||||||
// Time (seconds).
|
// Time (seconds).
|
||||||
time += samplerate;
|
time += samplerate;
|
||||||
sample.time = time;
|
sample.time = time * 1000;
|
||||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||||
|
|
||||||
// Initial gas mix.
|
// Initial gas mix.
|
||||||
if (time == samplerate && parser->initial != UNDEFINED) {
|
if (time == samplerate && parser->initial != UNDEFINED) {
|
||||||
sample.gasmix = parser->initial;
|
unsigned int idx = hw_ostc_find_gasmix_fixed (parser, parser->initial);
|
||||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
parser->gasmix[idx].active = 1;
|
||||||
|
sample.gasmix = idx;
|
||||||
|
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial setpoint (mbar).
|
// Initial setpoint (mbar).
|
||||||
if (time == samplerate && parser->initial_setpoint != UNDEFINED) {
|
if (time == samplerate && parser->initial_setpoint != UNDEFINED) {
|
||||||
sample.setpoint = parser->initial_setpoint / 100.0;
|
sample.setpoint = parser->initial_setpoint / 100.0;
|
||||||
if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
|
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial CNS (%).
|
// Initial CNS (%).
|
||||||
if (time == samplerate && parser->initial_cns != UNDEFINED) {
|
if (time == samplerate && parser->initial_cns != UNDEFINED) {
|
||||||
sample.cns = parser->initial_cns / 100.0;
|
sample.cns = parser->initial_cns / 100.0;
|
||||||
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
|
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depth (1/100 m).
|
// Depth (1/100 m).
|
||||||
unsigned int depth = array_uint16_le (data + offset);
|
unsigned int depth = array_uint16_le (data + offset);
|
||||||
sample.depth = depth / 100.0;
|
sample.depth = depth / 100.0;
|
||||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
|
|
||||||
// Extended sample info.
|
// Extended sample info.
|
||||||
@ -780,7 +907,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (sample.event.type && callback)
|
if (sample.event.type && callback)
|
||||||
callback (DC_SAMPLE_EVENT, sample, userdata);
|
callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||||
|
|
||||||
// Manual Gas Set & Change
|
// Manual Gas Set & Change
|
||||||
if (events & 0x10) {
|
if (events & 0x10) {
|
||||||
@ -790,19 +917,24 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
|||||||
}
|
}
|
||||||
unsigned int o2 = data[offset];
|
unsigned int o2 = data[offset];
|
||||||
unsigned int he = data[offset + 1];
|
unsigned int he = data[offset + 1];
|
||||||
unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, MANUAL);
|
unsigned int idx = hw_ostc_find_gasmix_manual (parser, o2, he, ccr);
|
||||||
if (idx >= parser->ngasmixes) {
|
if (idx >= parser->ngasmixes) {
|
||||||
if (idx >= NGASMIXES) {
|
if (idx >= NGASMIXES) {
|
||||||
ERROR (abstract->context, "Maximum number of gas mixes reached.");
|
ERROR (abstract->context, "Maximum number of gas mixes reached.");
|
||||||
return DC_STATUS_NOMEMORY;
|
return DC_STATUS_NOMEMORY;
|
||||||
}
|
}
|
||||||
|
parser->gasmix[idx].id = 0;
|
||||||
parser->gasmix[idx].oxygen = o2;
|
parser->gasmix[idx].oxygen = o2;
|
||||||
parser->gasmix[idx].helium = he;
|
parser->gasmix[idx].helium = he;
|
||||||
|
parser->gasmix[idx].type = 0;
|
||||||
|
parser->gasmix[idx].enabled = 1;
|
||||||
|
parser->gasmix[idx].active = 1;
|
||||||
|
parser->gasmix[idx].diluent = ccr;
|
||||||
parser->ngasmixes = idx + 1;
|
parser->ngasmixes = idx + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sample.gasmix = idx;
|
sample.gasmix = idx;
|
||||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
length -= 2;
|
length -= 2;
|
||||||
}
|
}
|
||||||
@ -813,15 +945,20 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
|||||||
ERROR (abstract->context, "Buffer overflow detected!");
|
ERROR (abstract->context, "Buffer overflow detected!");
|
||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
unsigned int idx = data[offset];
|
unsigned int id = data[offset];
|
||||||
if (idx < 1 || idx > parser->ngasmixes) {
|
if (parser->model == OSTC4 && ccr && id > parser->nfixed) {
|
||||||
ERROR(abstract->context, "Invalid gas mix.");
|
// Fix the OSTC4 diluent index.
|
||||||
|
id -= parser->nfixed;
|
||||||
|
}
|
||||||
|
if (id < 1 || id > parser->nfixed) {
|
||||||
|
ERROR(abstract->context, "Invalid gas mix (%u).", id);
|
||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
idx--; /* Convert to a zero based index. */
|
unsigned int idx = hw_ostc_find_gasmix_fixed (parser, id);
|
||||||
|
parser->gasmix[idx].active = 1;
|
||||||
sample.gasmix = idx;
|
sample.gasmix = idx;
|
||||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||||
tank = idx;
|
tank = id - 1;
|
||||||
offset++;
|
offset++;
|
||||||
length--;
|
length--;
|
||||||
}
|
}
|
||||||
@ -834,7 +971,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
|||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
sample.setpoint = data[offset] / 100.0;
|
sample.setpoint = data[offset] / 100.0;
|
||||||
if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
|
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||||
offset++;
|
offset++;
|
||||||
length--;
|
length--;
|
||||||
}
|
}
|
||||||
@ -848,19 +985,24 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
|||||||
|
|
||||||
unsigned int o2 = data[offset];
|
unsigned int o2 = data[offset];
|
||||||
unsigned int he = data[offset + 1];
|
unsigned int he = data[offset + 1];
|
||||||
unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, MANUAL);
|
unsigned int idx = hw_ostc_find_gasmix_manual (parser, o2, he, 0);
|
||||||
if (idx >= parser->ngasmixes) {
|
if (idx >= parser->ngasmixes) {
|
||||||
if (idx >= NGASMIXES) {
|
if (idx >= NGASMIXES) {
|
||||||
ERROR (abstract->context, "Maximum number of gas mixes reached.");
|
ERROR (abstract->context, "Maximum number of gas mixes reached.");
|
||||||
return DC_STATUS_NOMEMORY;
|
return DC_STATUS_NOMEMORY;
|
||||||
}
|
}
|
||||||
|
parser->gasmix[idx].id = 0;
|
||||||
parser->gasmix[idx].oxygen = o2;
|
parser->gasmix[idx].oxygen = o2;
|
||||||
parser->gasmix[idx].helium = he;
|
parser->gasmix[idx].helium = he;
|
||||||
|
parser->gasmix[idx].type = 0;
|
||||||
|
parser->gasmix[idx].enabled = 1;
|
||||||
|
parser->gasmix[idx].active = 1;
|
||||||
|
parser->gasmix[idx].diluent = 0;
|
||||||
parser->ngasmixes = idx + 1;
|
parser->ngasmixes = idx + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sample.gasmix = idx;
|
sample.gasmix = idx;
|
||||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
length -= 2;
|
length -= 2;
|
||||||
}
|
}
|
||||||
@ -892,7 +1034,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
|||||||
case TEMPERATURE:
|
case TEMPERATURE:
|
||||||
value = array_uint16_le (data + offset);
|
value = array_uint16_le (data + offset);
|
||||||
sample.temperature = value / 10.0;
|
sample.temperature = value / 10.0;
|
||||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||||
break;
|
break;
|
||||||
case DECO:
|
case DECO:
|
||||||
// Due to a firmware bug, the deco/ndl info is incorrect for
|
// Due to a firmware bug, the deco/ndl info is incorrect for
|
||||||
@ -907,7 +1049,8 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
|||||||
sample.deco.depth = 0.0;
|
sample.deco.depth = 0.0;
|
||||||
}
|
}
|
||||||
sample.deco.time = data[offset + 1] * 60;
|
sample.deco.time = data[offset + 1] * 60;
|
||||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
sample.deco.tts = 0;
|
||||||
|
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||||
break;
|
break;
|
||||||
case PPO2:
|
case PPO2:
|
||||||
for (unsigned int j = 0; j < 3; ++j) {
|
for (unsigned int j = 0; j < 3; ++j) {
|
||||||
@ -921,8 +1064,9 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
|||||||
}
|
}
|
||||||
if (count) {
|
if (count) {
|
||||||
for (unsigned int j = 0; j < 3; ++j) {
|
for (unsigned int j = 0; j < 3; ++j) {
|
||||||
sample.ppo2 = ppo2[j] / 100.0;
|
sample.ppo2.sensor = i;
|
||||||
if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
|
sample.ppo2.value = ppo2[j] / 100.0;
|
||||||
|
if (callback) callback (DC_SAMPLE_PPO2, &sample, userdata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -931,7 +1075,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
|||||||
sample.cns = array_uint16_le (data + offset) / 100.0;
|
sample.cns = array_uint16_le (data + offset) / 100.0;
|
||||||
else
|
else
|
||||||
sample.cns = data[offset] / 100.0;
|
sample.cns = data[offset] / 100.0;
|
||||||
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
|
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata);
|
||||||
break;
|
break;
|
||||||
case TANK:
|
case TANK:
|
||||||
value = array_uint16_le (data + offset);
|
value = array_uint16_le (data + offset);
|
||||||
@ -944,7 +1088,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
|||||||
(firmware >= OSTC3FW(10,40) && firmware <= OSTC3FW(10,50))) {
|
(firmware >= OSTC3FW(10,40) && firmware <= OSTC3FW(10,50))) {
|
||||||
sample.pressure.value /= 10.0;
|
sample.pressure.value /= 10.0;
|
||||||
}
|
}
|
||||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default: // Not yet used.
|
default: // Not yet used.
|
||||||
@ -964,7 +1108,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
|||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
sample.setpoint = data[offset] / 100.0;
|
sample.setpoint = data[offset] / 100.0;
|
||||||
if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
|
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||||
offset++;
|
offset++;
|
||||||
length--;
|
length--;
|
||||||
}
|
}
|
||||||
@ -978,19 +1122,24 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
|||||||
|
|
||||||
unsigned int o2 = data[offset];
|
unsigned int o2 = data[offset];
|
||||||
unsigned int he = data[offset + 1];
|
unsigned int he = data[offset + 1];
|
||||||
unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, MANUAL);
|
unsigned int idx = hw_ostc_find_gasmix_manual (parser, o2, he, 0);
|
||||||
if (idx >= parser->ngasmixes) {
|
if (idx >= parser->ngasmixes) {
|
||||||
if (idx >= NGASMIXES) {
|
if (idx >= NGASMIXES) {
|
||||||
ERROR (abstract->context, "Maximum number of gas mixes reached.");
|
ERROR (abstract->context, "Maximum number of gas mixes reached.");
|
||||||
return DC_STATUS_NOMEMORY;
|
return DC_STATUS_NOMEMORY;
|
||||||
}
|
}
|
||||||
|
parser->gasmix[idx].id = 0;
|
||||||
parser->gasmix[idx].oxygen = o2;
|
parser->gasmix[idx].oxygen = o2;
|
||||||
parser->gasmix[idx].helium = he;
|
parser->gasmix[idx].helium = he;
|
||||||
|
parser->gasmix[idx].type = 0;
|
||||||
|
parser->gasmix[idx].enabled = 1;
|
||||||
|
parser->gasmix[idx].active = 1;
|
||||||
|
parser->gasmix[idx].diluent = 0;
|
||||||
parser->ngasmixes = idx + 1;
|
parser->ngasmixes = idx + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sample.gasmix = idx;
|
sample.gasmix = idx;
|
||||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||||
offset += 2;
|
offset += 2;
|
||||||
length -= 2;
|
length -= 2;
|
||||||
}
|
}
|
||||||
@ -1008,7 +1157,50 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
|||||||
return DC_STATUS_DATAFORMAT;
|
return DC_STATUS_DATAFORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the disabled gas mixes from the fixed gas mixes.
|
||||||
|
unsigned int ndisabled = 0, nenabled = 0;
|
||||||
|
unsigned int count = parser->nfixed - parser->ndisabled;
|
||||||
|
for (unsigned int i = 0; i < count; ++i) {
|
||||||
|
if (parser->gasmix[i].enabled || parser->gasmix[i].active) {
|
||||||
|
// Move the fixed gas mix.
|
||||||
|
parser->gasmix[nenabled] = parser->gasmix[i];
|
||||||
|
nenabled++;
|
||||||
|
} else {
|
||||||
|
ndisabled++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move all the manual gas mixes.
|
||||||
|
memmove (parser->gasmix + nenabled, parser->gasmix + count,
|
||||||
|
(parser->ngasmixes - count) * sizeof (hw_ostc_gasmix_t));
|
||||||
|
memset (parser->gasmix + parser->ngasmixes - ndisabled, 0,
|
||||||
|
ndisabled * sizeof (hw_ostc_gasmix_t));
|
||||||
|
|
||||||
|
// Adjust the counts.
|
||||||
|
parser->ngasmixes -= ndisabled;
|
||||||
|
parser->ndisabled += ndisabled;
|
||||||
|
|
||||||
parser->cached = PROFILE;
|
parser->cached = PROFILE;
|
||||||
|
|
||||||
return DC_STATUS_SUCCESS;
|
return DC_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static dc_status_t
|
||||||
|
hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||||
|
{
|
||||||
|
hw_ostc_parser_t *parser = (hw_ostc_parser_t *) abstract;
|
||||||
|
|
||||||
|
// Cache the header data.
|
||||||
|
dc_status_t rc = hw_ostc_parser_cache (parser);
|
||||||
|
if (rc != DC_STATUS_SUCCESS)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
// Cache the profile data.
|
||||||
|
if (parser->cached < PROFILE) {
|
||||||
|
rc = hw_ostc_parser_internal_foreach (parser, NULL, NULL);
|
||||||
|
if (rc != DC_STATUS_SUCCESS)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hw_ostc_parser_internal_foreach (parser, callback, userdata);
|
||||||
|
}
|
||||||
|
|||||||
@ -24,7 +24,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h> // malloc, free
|
#include <stdlib.h> // malloc, free
|
||||||
#include <stdio.h> // snprintf
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "socket.h"
|
#include "socket.h"
|
||||||
@ -48,7 +47,6 @@
|
|||||||
#include "context-private.h"
|
#include "context-private.h"
|
||||||
#include "iostream-private.h"
|
#include "iostream-private.h"
|
||||||
#include "iterator-private.h"
|
#include "iterator-private.h"
|
||||||
#include "descriptor-private.h"
|
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
@ -227,7 +225,7 @@ dc_irda_iterator_new (dc_iterator_t **out, dc_context_t *context, dc_descriptor_
|
|||||||
INFO (context, "Discover: address=%08x, name=%s, charset=%02x, hints=%04x",
|
INFO (context, "Discover: address=%08x, name=%s, charset=%02x, hints=%04x",
|
||||||
address, name, charset, hints);
|
address, name, charset, hints);
|
||||||
|
|
||||||
if (!dc_descriptor_filter (descriptor, DC_TRANSPORT_IRDA, name, NULL)) {
|
if (!dc_descriptor_filter (descriptor, DC_TRANSPORT_IRDA, name)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,7 +312,7 @@ dc_irda_open (dc_iostream_t **out, dc_context_t *context, unsigned int address,
|
|||||||
peer.irdaDeviceID[1] = (address >> 8) & 0xFF;
|
peer.irdaDeviceID[1] = (address >> 8) & 0xFF;
|
||||||
peer.irdaDeviceID[2] = (address >> 16) & 0xFF;
|
peer.irdaDeviceID[2] = (address >> 16) & 0xFF;
|
||||||
peer.irdaDeviceID[3] = (address >> 24) & 0xFF;
|
peer.irdaDeviceID[3] = (address >> 24) & 0xFF;
|
||||||
snprintf (peer.irdaServiceName, sizeof(peer.irdaServiceName), "LSAP-SEL%u", lsap);
|
dc_platform_snprintf (peer.irdaServiceName, sizeof(peer.irdaServiceName), "LSAP-SEL%u", lsap);
|
||||||
#else
|
#else
|
||||||
struct sockaddr_irda peer;
|
struct sockaddr_irda peer;
|
||||||
peer.sir_family = AF_IRDA;
|
peer.sir_family = AF_IRDA;
|
||||||
|
|||||||
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