Compare commits
88 Commits
release-0.
...
master
| 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 |
22
.github/workflows/build.yml
vendored
22
.github/workflows/build.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
||||
CC: ${{ matrix.compiler }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install libbluetooth-dev libusb-1.0-0-dev
|
||||
- run: autoreconf --install --force
|
||||
@ -30,7 +30,7 @@ jobs:
|
||||
run: |
|
||||
make install DESTDIR=$PWD/artifacts
|
||||
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ github.job }}-${{ matrix.compiler }}
|
||||
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
|
||||
@ -50,7 +50,7 @@ jobs:
|
||||
CC: ${{ matrix.compiler }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
run: brew install autoconf automake libtool hidapi libusb
|
||||
- run: autoreconf --install --force
|
||||
@ -61,7 +61,7 @@ jobs:
|
||||
run: |
|
||||
make install DESTDIR=$PWD/artifacts
|
||||
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ github.job }}-${{ matrix.compiler }}
|
||||
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
|
||||
@ -78,7 +78,7 @@ jobs:
|
||||
arch: [i686, x86_64]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install gcc-mingw-w64 binutils-mingw-w64 mingw-w64-tools
|
||||
- name: Install libusb
|
||||
@ -118,7 +118,7 @@ jobs:
|
||||
run: |
|
||||
make install DESTDIR=$PWD/artifacts
|
||||
tar -czf ${{ github.job }}-${{ matrix.arch }}.tar.gz -C artifacts usr
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ github.job }}-${{ matrix.arch }}
|
||||
path: ${{ github.job }}-${{ matrix.arch }}.tar.gz
|
||||
@ -138,7 +138,7 @@ jobs:
|
||||
CONFIGURATION: Release
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
install: autoconf automake libtool pkg-config make gcc
|
||||
@ -147,9 +147,9 @@ jobs:
|
||||
./configure --prefix=/usr
|
||||
make -C src revision.h
|
||||
shell: msys2 {0}
|
||||
- uses: microsoft/setup-msbuild@v1
|
||||
- uses: microsoft/setup-msbuild@v2
|
||||
- run: msbuild -m -p:Platform=${{ matrix.platform }} -p:Configuration=${{ env.CONFIGURATION }} contrib/msvc/libdivecomputer.vcxproj
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ github.job }}-${{ matrix.platform }}
|
||||
path: contrib/msvc/${{ matrix.platform }}/${{ env.CONFIGURATION }}/bin
|
||||
@ -161,13 +161,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- 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@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ github.job }}
|
||||
path: contrib/android/libs
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -9,7 +9,7 @@ jobs:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Version number
|
||||
id: version
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
# Versioning.
|
||||
m4_define([dc_version_major],[0])
|
||||
m4_define([dc_version_minor],[8])
|
||||
m4_define([dc_version_micro],[1])
|
||||
m4_define([dc_version_minor],[9])
|
||||
m4_define([dc_version_micro],[0])
|
||||
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]))
|
||||
|
||||
|
||||
@ -71,6 +71,7 @@ LOCAL_SRC_FILES := \
|
||||
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 \
|
||||
|
||||
@ -239,6 +239,7 @@
|
||||
<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" />
|
||||
@ -331,7 +332,6 @@
|
||||
<ClInclude Include="..\..\src\cressi_leonardo.h" />
|
||||
<ClInclude Include="..\..\src\deepblu_cosmiq.h" />
|
||||
<ClInclude Include="..\..\src\deepsix_excursion.h" />
|
||||
<ClInclude Include="..\..\src\descriptor-private.h" />
|
||||
<ClInclude Include="..\..\src\device-private.h" />
|
||||
<ClInclude Include="..\..\src\diverite_nitekq.h" />
|
||||
<ClInclude Include="..\..\src\divesoft_freedom.h" />
|
||||
@ -358,6 +358,7 @@
|
||||
<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" />
|
||||
|
||||
@ -32,7 +32,6 @@ MANPAGES = \
|
||||
dc_parser_get_field.3 \
|
||||
dc_parser_new.3 \
|
||||
dc_parser_samples_foreach.3 \
|
||||
dc_parser_set_data.3 \
|
||||
dc_bluetooth_open.3 \
|
||||
dc_bluetooth_iterator_new.3 \
|
||||
dc_bluetooth_device_get_address.3 \
|
||||
|
||||
@ -53,7 +53,7 @@ with
|
||||
Each dive invokes
|
||||
.Fa callback
|
||||
with the dive data, which should be parsed with
|
||||
.Xr dc_parser_set_data 3 ,
|
||||
.Xr dc_parser_new 3 ,
|
||||
and the binary fingerprint of the dive.
|
||||
The fingerprint can be used to record the newest dive and stop
|
||||
processing (on subsequent invocations) when the same dive fingerprint is
|
||||
@ -72,7 +72,7 @@ If
|
||||
returns zero, this will not be reflected in the return value (usually
|
||||
.Dv DC_STATUS_SUCCESS ) .
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_parser_set_data 3
|
||||
.Xr dc_parser_new 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
Extract the date and time of a dive,
|
||||
.Fa parser ,
|
||||
previously initialised with
|
||||
.Xr dc_parser_set_data 3 .
|
||||
.Xr dc_parser_new 3 .
|
||||
This returns the broken-down time-stamp of the dive in the local time of
|
||||
the dive.
|
||||
.Pp
|
||||
@ -57,7 +57,7 @@ messages on further failure.
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_datetime_gmtime 3 ,
|
||||
.Xr dc_datetime_localtime 3 ,
|
||||
.Xr dc_parser_set_data 3
|
||||
.Xr dc_parser_new 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
Extract a field from a dive,
|
||||
.Fa parser ,
|
||||
previously initialised with
|
||||
.Xr dc_parser_set_data 3 .
|
||||
.Xr dc_parser_new 3 .
|
||||
The
|
||||
.Fa value
|
||||
field type depends upon the
|
||||
@ -187,7 +187,7 @@ if the field was retrieved,
|
||||
if the field is not supported by the device, or other error messages on
|
||||
further failure.
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_parser_set_data 3
|
||||
.Xr dc_parser_new 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -39,8 +39,6 @@
|
||||
.Fa "dc_parser_t **parser"
|
||||
.Fa "dc_context_t *context"
|
||||
.Fa "dc_descriptor_t *descriptor"
|
||||
.Fa "unsigned int devtime"
|
||||
.Fa "dc_ticks_t systime"
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
Creates a parser for a single dive extracted from the dive computer with
|
||||
@ -55,10 +53,6 @@ parameter; and
|
||||
.Nm dc_parser_new2 ,
|
||||
which is given device values (model, etc.) directly.
|
||||
.Pp
|
||||
After filling in the
|
||||
.Fa parser
|
||||
parameter, one usually sets parser data with
|
||||
.Xr dc_parser_set_data 3 .
|
||||
The pointer must later be freed with
|
||||
.Xr dc_parser_destroy 3 .
|
||||
.Sh RETURN VALUES
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
.Ft "typedef void"
|
||||
.Fo "(*dc_sample_callback_t)"
|
||||
.Fa "dc_sample_type_t type"
|
||||
.Fa "dc_sample_value_t value"
|
||||
.Fa "const dc_sample_value_t *value"
|
||||
.Fa "void *userdata"
|
||||
.Fc
|
||||
.Ft dc_status_t
|
||||
@ -42,7 +42,7 @@
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
Extract the samples taken during a dive as previously initialised with
|
||||
.Xr dc_parser_set_data 3 .
|
||||
.Xr dc_parser_new 3 .
|
||||
Each sample is passed to
|
||||
.Fa callback
|
||||
with the
|
||||
@ -63,7 +63,7 @@ closed.
|
||||
The following sample types may be raised:
|
||||
.Bl -tag -width Ds
|
||||
.It Dv DC_SAMPLE_TIME
|
||||
The time of the sample taken in seconds after the dive began.
|
||||
The time of the sample taken in milliseconds after the dive began.
|
||||
Set in the
|
||||
.Fa time
|
||||
field.
|
||||
@ -184,7 +184,7 @@ Returns
|
||||
.Dv DC_STATUS_OK
|
||||
on success and another code on failure.
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_parser_set_data 3
|
||||
.Xr dc_parser_new 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
.\"
|
||||
.\" libdivecomputer
|
||||
.\"
|
||||
.\" Copyright (C) 2017 Kristaps Dzonsons <kristaps@bsd.lv>
|
||||
.\"
|
||||
.\" This library is free software; you can redistribute it and/or
|
||||
.\" modify it under the terms of the GNU Lesser General Public
|
||||
.\" License as published by the Free Software Foundation; either
|
||||
.\" version 2.1 of the License, or (at your option) any later version.
|
||||
.\"
|
||||
.\" This library is distributed in the hope that it will be useful,
|
||||
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
.\" Lesser General Public License for more details.
|
||||
.\"
|
||||
.\" You should have received a copy of the GNU Lesser General Public
|
||||
.\" License along with this library; if not, write to the Free Software
|
||||
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
.\" MA 02110-1301 USA
|
||||
.\"
|
||||
.Dd January 5, 2017
|
||||
.Dt DC_PARSER_SET_DATA 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm dc_parser_set_data
|
||||
.Nd assigns parse data to a dive parser
|
||||
.Sh LIBRARY
|
||||
.Lb libdivecomputer
|
||||
.Sh SYNOPSIS
|
||||
.In libdivecomputer/parser.h
|
||||
.Ft dc_status_t
|
||||
.Fo dc_parser_set_data
|
||||
.Fa "dc_parser_t *parser"
|
||||
.Fa "const unsigned char *data"
|
||||
.Fa "unsigned int size"
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
Assigns the binary sequence
|
||||
.Fa data
|
||||
of length
|
||||
.Fa size
|
||||
bytes to
|
||||
.Fa parser ,
|
||||
which was created with
|
||||
.Xr dc_parser_new 3 .
|
||||
How the data is parsed depends upon the values provided to
|
||||
.Xr dc_parser_new 3 .
|
||||
The data usually comes from the callback assigned to
|
||||
.Xr dc_device_foreach 3 .
|
||||
.Sh RETURN VALUES
|
||||
Returns
|
||||
.Dv DC_STATUS_OK
|
||||
on success and another code on failure.
|
||||
.Sh SEE ALSO
|
||||
.Xr dc_device_foreach 3 ,
|
||||
.Xr dc_parser_new 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Lb libdivecomputer
|
||||
library was written by
|
||||
.An Jef Driesen ,
|
||||
.Mt jef@libdivecomputer.org .
|
||||
The manpages were written by
|
||||
.An Kristaps Dzonsons ,
|
||||
.Mt kristaps@bsd.lv .
|
||||
@ -82,9 +82,7 @@ Iterate over all dives with
|
||||
.Xr dc_device_foreach 3 .
|
||||
.It
|
||||
For each iterated dive, create a new parser with
|
||||
.Xr dc_parser_new 3
|
||||
and set the parsed data with
|
||||
.Xr dc_parser_set_data 3 .
|
||||
.Xr dc_parser_new 3 .
|
||||
.It
|
||||
Get attributes of the parsed dive with
|
||||
.Xr dc_parser_get_field 3 .
|
||||
|
||||
@ -72,6 +72,7 @@ static const backend_table_t g_backends[] = {
|
||||
{"vtpro", DC_FAMILY_OCEANIC_VTPRO, 0x4245},
|
||||
{"veo250", DC_FAMILY_OCEANIC_VEO250, 0x424C},
|
||||
{"atom2", DC_FAMILY_OCEANIC_ATOM2, 0x4342},
|
||||
{"i330r", DC_FAMILY_PELAGIC_I330R, 0x4744},
|
||||
{"nemo", DC_FAMILY_MARES_NEMO, 0},
|
||||
{"puck", DC_FAMILY_MARES_PUCK, 7},
|
||||
{"darwin", DC_FAMILY_MARES_DARWIN, 0},
|
||||
|
||||
@ -80,20 +80,12 @@ dive_cb (const unsigned char *data, unsigned int size, const unsigned char *fing
|
||||
|
||||
// Create the parser.
|
||||
message ("Creating the parser.\n");
|
||||
rc = dc_parser_new (&parser, divedata->device);
|
||||
rc = dc_parser_new (&parser, divedata->device, data, size);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR ("Error creating the parser.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Register the data.
|
||||
message ("Registering the data.\n");
|
||||
rc = dc_parser_set_data (parser, data, size);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR ("Error registering the data.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Parse the dive data.
|
||||
message ("Parsing the dive data.\n");
|
||||
rc = dctool_output_write (divedata->output, parser, data, size, fingerprint, fsize);
|
||||
|
||||
@ -54,17 +54,17 @@ parse (dc_buffer_t *buffer, dc_context_t *context, dc_descriptor_t *descriptor,
|
||||
|
||||
// Create the parser.
|
||||
message ("Creating the parser.\n");
|
||||
rc = dc_parser_new2 (&parser, context, descriptor, devtime, systime);
|
||||
rc = dc_parser_new2 (&parser, context, descriptor, data, size);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR ("Error creating the parser.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Register the data.
|
||||
message ("Registering the data.\n");
|
||||
rc = dc_parser_set_data (parser, data, size);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR ("Error registering the data.");
|
||||
// Set the clock.
|
||||
message ("Setting the clock.\n");
|
||||
rc = dc_parser_set_clock (parser, devtime, systime);
|
||||
if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
|
||||
ERROR ("Error setting the clock.");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
@ -90,7 +90,7 @@ convert_volume (double value, dctool_units_t units)
|
||||
}
|
||||
|
||||
static void
|
||||
sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata)
|
||||
sample_cb (dc_sample_type_t type, const dc_sample_value_t *value, void *userdata)
|
||||
{
|
||||
static const char *events[] = {
|
||||
"none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter",
|
||||
@ -104,64 +104,80 @@ sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata)
|
||||
|
||||
sample_data_t *sampledata = (sample_data_t *) userdata;
|
||||
|
||||
unsigned int seconds = 0, milliseconds = 0;
|
||||
|
||||
switch (type) {
|
||||
case DC_SAMPLE_TIME:
|
||||
seconds = value->time / 1000;
|
||||
milliseconds = value->time % 1000;
|
||||
if (sampledata->nsamples++)
|
||||
fprintf (sampledata->ostream, "</sample>\n");
|
||||
fprintf (sampledata->ostream, "<sample>\n");
|
||||
fprintf (sampledata->ostream, " <time>%02u:%02u</time>\n", value.time / 60, value.time % 60);
|
||||
if (milliseconds) {
|
||||
fprintf (sampledata->ostream, " <time>%02u:%02u.%03u</time>\n", seconds / 60, seconds % 60, milliseconds);
|
||||
} else {
|
||||
fprintf (sampledata->ostream, " <time>%02u:%02u</time>\n", seconds / 60, seconds % 60);
|
||||
}
|
||||
break;
|
||||
case DC_SAMPLE_DEPTH:
|
||||
fprintf (sampledata->ostream, " <depth>%.2f</depth>\n",
|
||||
convert_depth(value.depth, sampledata->units));
|
||||
convert_depth(value->depth, sampledata->units));
|
||||
break;
|
||||
case DC_SAMPLE_PRESSURE:
|
||||
fprintf (sampledata->ostream, " <pressure tank=\"%u\">%.2f</pressure>\n",
|
||||
value.pressure.tank,
|
||||
convert_pressure(value.pressure.value, sampledata->units));
|
||||
value->pressure.tank,
|
||||
convert_pressure(value->pressure.value, sampledata->units));
|
||||
break;
|
||||
case DC_SAMPLE_TEMPERATURE:
|
||||
fprintf (sampledata->ostream, " <temperature>%.2f</temperature>\n",
|
||||
convert_temperature(value.temperature, sampledata->units));
|
||||
convert_temperature(value->temperature, sampledata->units));
|
||||
break;
|
||||
case DC_SAMPLE_EVENT:
|
||||
if (value.event.type != SAMPLE_EVENT_GASCHANGE && value.event.type != SAMPLE_EVENT_GASCHANGE2) {
|
||||
if (value->event.type != SAMPLE_EVENT_GASCHANGE && value->event.type != SAMPLE_EVENT_GASCHANGE2) {
|
||||
fprintf (sampledata->ostream, " <event type=\"%u\" time=\"%u\" flags=\"%u\" value=\"%u\">%s</event>\n",
|
||||
value.event.type, value.event.time, value.event.flags, value.event.value, events[value.event.type]);
|
||||
value->event.type, value->event.time, value->event.flags, value->event.value, events[value->event.type]);
|
||||
}
|
||||
break;
|
||||
case DC_SAMPLE_RBT:
|
||||
fprintf (sampledata->ostream, " <rbt>%u</rbt>\n", value.rbt);
|
||||
fprintf (sampledata->ostream, " <rbt>%u</rbt>\n", value->rbt);
|
||||
break;
|
||||
case DC_SAMPLE_HEARTBEAT:
|
||||
fprintf (sampledata->ostream, " <heartbeat>%u</heartbeat>\n", value.heartbeat);
|
||||
fprintf (sampledata->ostream, " <heartbeat>%u</heartbeat>\n", value->heartbeat);
|
||||
break;
|
||||
case DC_SAMPLE_BEARING:
|
||||
fprintf (sampledata->ostream, " <bearing>%u</bearing>\n", value.bearing);
|
||||
fprintf (sampledata->ostream, " <bearing>%u</bearing>\n", value->bearing);
|
||||
break;
|
||||
case DC_SAMPLE_VENDOR:
|
||||
fprintf (sampledata->ostream, " <vendor type=\"%u\" size=\"%u\">", value.vendor.type, value.vendor.size);
|
||||
for (unsigned int i = 0; i < value.vendor.size; ++i)
|
||||
fprintf (sampledata->ostream, "%02X", ((const unsigned char *) value.vendor.data)[i]);
|
||||
fprintf (sampledata->ostream, " <vendor type=\"%u\" size=\"%u\">", value->vendor.type, value->vendor.size);
|
||||
for (unsigned int i = 0; i < value->vendor.size; ++i)
|
||||
fprintf (sampledata->ostream, "%02X", ((const unsigned char *) value->vendor.data)[i]);
|
||||
fprintf (sampledata->ostream, "</vendor>\n");
|
||||
break;
|
||||
case DC_SAMPLE_SETPOINT:
|
||||
fprintf (sampledata->ostream, " <setpoint>%.2f</setpoint>\n", value.setpoint);
|
||||
fprintf (sampledata->ostream, " <setpoint>%.2f</setpoint>\n", value->setpoint);
|
||||
break;
|
||||
case DC_SAMPLE_PPO2:
|
||||
fprintf (sampledata->ostream, " <ppo2>%.2f</ppo2>\n", value.ppo2);
|
||||
if (value->ppo2.sensor != DC_SENSOR_NONE) {
|
||||
fprintf (sampledata->ostream, " <ppo2 sensor=\"%u\">%.2f</ppo2>\n", value->ppo2.sensor, value->ppo2.value);
|
||||
} else {
|
||||
fprintf (sampledata->ostream, " <ppo2>%.2f</ppo2>\n", value->ppo2.value);
|
||||
}
|
||||
break;
|
||||
case DC_SAMPLE_CNS:
|
||||
fprintf (sampledata->ostream, " <cns>%.1f</cns>\n", value.cns * 100.0);
|
||||
fprintf (sampledata->ostream, " <cns>%.1f</cns>\n", value->cns * 100.0);
|
||||
break;
|
||||
case DC_SAMPLE_DECO:
|
||||
fprintf (sampledata->ostream, " <deco time=\"%u\" depth=\"%.2f\">%s</deco>\n",
|
||||
value.deco.time,
|
||||
convert_depth(value.deco.depth, sampledata->units),
|
||||
decostop[value.deco.type]);
|
||||
value->deco.time,
|
||||
convert_depth(value->deco.depth, sampledata->units),
|
||||
decostop[value->deco.type]);
|
||||
if (value->deco.tts) {
|
||||
fprintf (sampledata->ostream, " <tts>%u</tts>\n",
|
||||
value->deco.tts);
|
||||
}
|
||||
break;
|
||||
case DC_SAMPLE_GASMIX:
|
||||
fprintf (sampledata->ostream, " <gasmix>%u</gasmix>\n", value.gasmix);
|
||||
fprintf (sampledata->ostream, " <gasmix>%u</gasmix>\n", value->gasmix);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -322,11 +338,19 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
||||
"<gasmix>\n"
|
||||
" <he>%.1f</he>\n"
|
||||
" <o2>%.1f</o2>\n"
|
||||
" <n2>%.1f</n2>\n"
|
||||
"</gasmix>\n",
|
||||
" <n2>%.1f</n2>\n",
|
||||
gasmix.helium * 100.0,
|
||||
gasmix.oxygen * 100.0,
|
||||
gasmix.nitrogen * 100.0);
|
||||
if (gasmix.usage) {
|
||||
const char *usage[] = {"none", "oxygen", "diluent", "sidemount"};
|
||||
fprintf (output->ostream,
|
||||
" <usage>%s</usage>\n",
|
||||
usage[gasmix.usage]);
|
||||
}
|
||||
fprintf (output->ostream,
|
||||
"</gasmix>\n");
|
||||
|
||||
}
|
||||
|
||||
// Parse the tanks.
|
||||
@ -354,6 +378,12 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
||||
" <gasmix>%u</gasmix>\n",
|
||||
tank.gasmix);
|
||||
}
|
||||
if (tank.usage) {
|
||||
const char *usage[] = {"none", "oxygen", "diluent", "sidemount"};
|
||||
fprintf (output->ostream,
|
||||
" <usage>%s</usage>\n",
|
||||
usage[tank.usage]);
|
||||
}
|
||||
if (tank.type != DC_TANKVOLUME_NONE) {
|
||||
fprintf (output->ostream,
|
||||
" <type>%s</type>\n"
|
||||
@ -420,8 +450,14 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
|
||||
}
|
||||
|
||||
if (status != DC_STATUS_UNSUPPORTED) {
|
||||
fprintf (output->ostream, "<salinity type=\"%u\">%.1f</salinity>\n",
|
||||
salinity.type, salinity.density);
|
||||
const char *names[] = {"fresh", "salt"};
|
||||
if (salinity.density) {
|
||||
fprintf (output->ostream, "<salinity density=\"%.1f\">%s</salinity>\n",
|
||||
salinity.density, names[salinity.type]);
|
||||
} else {
|
||||
fprintf (output->ostream, "<salinity>%s</salinity>\n",
|
||||
names[salinity.type]);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the atmospheric pressure.
|
||||
|
||||
@ -36,9 +36,6 @@ atomics_cobalt_device_version (dc_device_t *device, unsigned char data[], unsign
|
||||
dc_status_t
|
||||
atomics_cobalt_device_set_simulation (dc_device_t *device, unsigned int simulation);
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -33,6 +33,21 @@ extern "C" {
|
||||
*/
|
||||
#define DC_IOCTL_BLE_GET_NAME DC_IOCTL_IOR('b', 0, DC_IOCTL_SIZE_VARIABLE)
|
||||
|
||||
/**
|
||||
* Get the bluetooth authentication PIN code.
|
||||
*
|
||||
* The data format is a NULL terminated string.
|
||||
*/
|
||||
#define DC_IOCTL_BLE_GET_PINCODE DC_IOCTL_IOR('b', 1, DC_IOCTL_SIZE_VARIABLE)
|
||||
|
||||
/**
|
||||
* Get/set the bluetooth authentication access code.
|
||||
*
|
||||
* The data format is a variable sized byte array.
|
||||
*/
|
||||
#define DC_IOCTL_BLE_GET_ACCESSCODE DC_IOCTL_IOR('b', 2, DC_IOCTL_SIZE_VARIABLE)
|
||||
#define DC_IOCTL_BLE_SET_ACCESSCODE DC_IOCTL_IOW('b', 2, DC_IOCTL_SIZE_VARIABLE)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -74,6 +74,7 @@ typedef enum dc_family_t {
|
||||
DC_FAMILY_OCEANIC_VTPRO = (4 << 16),
|
||||
DC_FAMILY_OCEANIC_VEO250,
|
||||
DC_FAMILY_OCEANIC_ATOM2,
|
||||
DC_FAMILY_PELAGIC_I330R,
|
||||
/* Mares */
|
||||
DC_FAMILY_MARES_NEMO = (5 << 16),
|
||||
DC_FAMILY_MARES_PUCK,
|
||||
|
||||
@ -29,29 +29,96 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* Opaque object representing a supported dive computer.
|
||||
*/
|
||||
typedef struct dc_descriptor_t dc_descriptor_t;
|
||||
|
||||
/**
|
||||
* Create an iterator to enumerate the supported dive computers.
|
||||
*
|
||||
* @param[out] iterator A location to store the iterator.
|
||||
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
|
||||
* on failure.
|
||||
*/
|
||||
dc_status_t
|
||||
dc_descriptor_iterator (dc_iterator_t **iterator);
|
||||
|
||||
/**
|
||||
* Free the device descriptor.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
*/
|
||||
void
|
||||
dc_descriptor_free (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Get the vendor name of the dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @returns The vendor name of the dive computer on success, or NULL on failure.
|
||||
*/
|
||||
const char *
|
||||
dc_descriptor_get_vendor (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Get the product name of the dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @returns The product name of the dive computer on success, or NULL on
|
||||
* failure.
|
||||
*/
|
||||
const char *
|
||||
dc_descriptor_get_product (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Get the family type of the dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @returns The family type of the dive computer on success, or DC_FAMILY_NULL
|
||||
* on failure.
|
||||
*/
|
||||
dc_family_t
|
||||
dc_descriptor_get_type (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Get the model number of the dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @returns The model number of the dive computer on success, or zero on
|
||||
* failure.
|
||||
*/
|
||||
unsigned int
|
||||
dc_descriptor_get_model (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Get all transports supported by the dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @returns A bitmask with all the transports supported by the dive computer on
|
||||
* success, or DC_TRANSPORT_NONE on failure.
|
||||
*/
|
||||
unsigned int
|
||||
dc_descriptor_get_transports (dc_descriptor_t *descriptor);
|
||||
|
||||
/**
|
||||
* Check if a low-level I/O device matches a supported dive computer.
|
||||
*
|
||||
* @param[in] descriptor A valid device descriptor.
|
||||
* @param[in] transport The transport type of the I/O device.
|
||||
* @param[in] userdata A pointer to a transport specific data structure:
|
||||
* - DC_TRANSPORT_SERIAL: Name of the device node (string)
|
||||
* - DC_TRANSPORT_USB: USB VID/PID (#dc_usb_desc_t)
|
||||
* - DC_TRANSPORT_USBHID: USB VID/PID (#dc_usbhid_desc_t)
|
||||
* - DC_TRANSPORT_IRDA: IrDA device name (string)
|
||||
* - DC_TRANSPORT_BLUETOOTH: Bluetooth device name (string)
|
||||
* - DC_TRANSPORT_BLE: Bluetooth device name (string)
|
||||
* @returns Non-zero if the device matches a supported dive computer, or zero if
|
||||
* there is no match.
|
||||
*/
|
||||
int
|
||||
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -141,12 +141,21 @@ typedef struct dc_salinity_t {
|
||||
double density;
|
||||
} 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 {
|
||||
double helium;
|
||||
double oxygen;
|
||||
double nitrogen;
|
||||
dc_usage_t usage;
|
||||
} dc_gasmix_t;
|
||||
|
||||
#define DC_SENSOR_NONE 0xFFFFFFFF
|
||||
#define DC_GASMIX_UNKNOWN 0xFFFFFFFF
|
||||
|
||||
typedef enum dc_tankvolume_t {
|
||||
@ -185,6 +194,7 @@ typedef struct dc_tank_t {
|
||||
double workpressure; /* Work pressure (bar) */
|
||||
double beginpressure; /* Begin pressure (bar) */
|
||||
double endpressure; /* End pressure (bar) */
|
||||
dc_usage_t usage;
|
||||
} dc_tank_t;
|
||||
|
||||
typedef enum dc_decomodel_type_t {
|
||||
@ -225,7 +235,7 @@ typedef struct dc_decomodel_t {
|
||||
} dc_decomodel_t;
|
||||
|
||||
typedef union dc_sample_value_t {
|
||||
unsigned int time;
|
||||
unsigned int time; /* Milliseconds */
|
||||
double depth;
|
||||
struct {
|
||||
unsigned int tank;
|
||||
@ -247,25 +257,29 @@ typedef union dc_sample_value_t {
|
||||
const void *data;
|
||||
} vendor;
|
||||
double setpoint;
|
||||
double ppo2;
|
||||
struct {
|
||||
unsigned int sensor;
|
||||
double value;
|
||||
} ppo2;
|
||||
double cns;
|
||||
struct {
|
||||
unsigned int type;
|
||||
unsigned int time;
|
||||
double depth;
|
||||
unsigned int tts;
|
||||
} deco;
|
||||
unsigned int gasmix; /* Gas mix index */
|
||||
} dc_sample_value_t;
|
||||
|
||||
typedef struct dc_parser_t dc_parser_t;
|
||||
|
||||
typedef void (*dc_sample_callback_t) (dc_sample_type_t type, dc_sample_value_t value, void *userdata);
|
||||
typedef void (*dc_sample_callback_t) (dc_sample_type_t type, const dc_sample_value_t *value, void *userdata);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_new (dc_parser_t **parser, dc_device_t *device);
|
||||
dc_parser_new (dc_parser_t **parser, dc_device_t *device, const unsigned char data[], size_t size);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_new2 (dc_parser_t **parser, dc_context_t *context, dc_descriptor_t *descriptor, unsigned int devtime, dc_ticks_t systime);
|
||||
dc_parser_new2 (dc_parser_t **parser, dc_context_t *context, dc_descriptor_t *descriptor, const unsigned char data[], size_t size);
|
||||
|
||||
dc_family_t
|
||||
dc_parser_get_type (dc_parser_t *parser);
|
||||
@ -279,9 +293,6 @@ dc_parser_set_atmospheric (dc_parser_t *parser, double atmospheric);
|
||||
dc_status_t
|
||||
dc_parser_set_density (dc_parser_t *parser, double density);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_set_data (dc_parser_t *parser, const unsigned char *data, unsigned int size);
|
||||
|
||||
dc_status_t
|
||||
dc_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime);
|
||||
|
||||
|
||||
@ -35,9 +35,6 @@ extern "C" {
|
||||
dc_status_t
|
||||
reefnet_sensus_device_get_handshake (dc_device_t *device, unsigned char data[], unsigned int size);
|
||||
|
||||
dc_status_t
|
||||
reefnet_sensus_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -38,9 +38,6 @@ reefnet_sensuspro_device_get_handshake (dc_device_t *device, unsigned char data[
|
||||
dc_status_t
|
||||
reefnet_sensuspro_device_write_interval (dc_device_t *device, unsigned char interval);
|
||||
|
||||
dc_status_t
|
||||
reefnet_sensuspro_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -56,9 +56,6 @@ reefnet_sensusultra_device_write_parameter (dc_device_t *device, reefnet_sensusu
|
||||
dc_status_t
|
||||
reefnet_sensusultra_device_sense (dc_device_t *device, unsigned char data[], unsigned int size);
|
||||
|
||||
dc_status_t
|
||||
reefnet_sensusultra_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -86,6 +86,14 @@ typedef enum dc_usb_recipient_t {
|
||||
DC_USB_RECIPIENT_OTHER = 0x03,
|
||||
} dc_usb_recipient_t;
|
||||
|
||||
/**
|
||||
* USB device descriptor.
|
||||
*/
|
||||
typedef struct dc_usb_desc_t {
|
||||
unsigned short vid;
|
||||
unsigned short pid;
|
||||
} dc_usb_desc_t;
|
||||
|
||||
/**
|
||||
* Opaque object representing a USB device.
|
||||
*/
|
||||
|
||||
@ -32,6 +32,14 @@
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* USB HID device descriptor.
|
||||
*/
|
||||
typedef struct dc_usbhid_desc_t {
|
||||
unsigned short vid;
|
||||
unsigned short pid;
|
||||
} dc_usbhid_desc_t;
|
||||
|
||||
/**
|
||||
* Opaque object representing a USB HID device.
|
||||
*/
|
||||
|
||||
@ -16,7 +16,7 @@ endif
|
||||
|
||||
libdivecomputer_la_SOURCES = \
|
||||
version.c \
|
||||
descriptor-private.h descriptor.c \
|
||||
descriptor.c \
|
||||
iostream-private.h iostream.c \
|
||||
iterator-private.h iterator.c \
|
||||
common-private.h common.c \
|
||||
@ -43,6 +43,7 @@ libdivecomputer_la_SOURCES = \
|
||||
oceanic_atom2.h oceanic_atom2.c oceanic_atom2_parser.c \
|
||||
oceanic_veo250.h oceanic_veo250.c oceanic_veo250_parser.c \
|
||||
oceanic_vtpro.h oceanic_vtpro.c oceanic_vtpro_parser.c \
|
||||
pelagic_i330r.h pelagic_i330r.c \
|
||||
mares_common.h mares_common.c \
|
||||
mares_nemo.h mares_nemo.c mares_nemo_parser.c \
|
||||
mares_puck.h mares_puck.c \
|
||||
|
||||
11
src/array.c
11
src/array.c
@ -404,3 +404,14 @@ signextend (unsigned int value, unsigned int nbits)
|
||||
else
|
||||
return value & mask;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
popcount (unsigned int value)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
while (value) {
|
||||
value &= value - 1;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -126,6 +126,9 @@ dec2bcd (unsigned char value);
|
||||
unsigned int
|
||||
signextend (unsigned int value, unsigned int nbits);
|
||||
|
||||
unsigned int
|
||||
popcount (unsigned int value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -41,6 +41,8 @@
|
||||
|
||||
#define FP_OFFSET 20
|
||||
|
||||
#define SZ_HEADER 228
|
||||
|
||||
#define SZ_MEMORY1 (29 * 64 * 1024) // Cobalt 1
|
||||
#define SZ_MEMORY2 (41 * 64 * 1024) // Cobalt 2
|
||||
#define SZ_VERSION 14
|
||||
@ -347,6 +349,12 @@ atomics_cobalt_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (size < SZ_HEADER) {
|
||||
ERROR (abstract->context, "Dive header is too small (%u).", size);
|
||||
dc_buffer_free (buffer);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
if (memcmp (data + FP_OFFSET, device->fingerprint, sizeof (device->fingerprint)) == 0) {
|
||||
dc_buffer_free (buffer);
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
atomics_cobalt_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
atomics_cobalt_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -43,7 +43,6 @@ struct atomics_cobalt_parser_t {
|
||||
double hydrostatic;
|
||||
};
|
||||
|
||||
static dc_status_t atomics_cobalt_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t atomics_cobalt_parser_set_density (dc_parser_t *abstract, double density);
|
||||
static dc_status_t atomics_cobalt_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
@ -52,7 +51,6 @@ static dc_status_t atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract,
|
||||
static const dc_parser_vtable_t atomics_cobalt_parser_vtable = {
|
||||
sizeof(atomics_cobalt_parser_t),
|
||||
DC_FAMILY_ATOMICS_COBALT,
|
||||
atomics_cobalt_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
atomics_cobalt_parser_set_density, /* set_density */
|
||||
@ -64,7 +62,7 @@ static const dc_parser_vtable_t atomics_cobalt_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
atomics_cobalt_parser_t *parser = NULL;
|
||||
|
||||
@ -72,7 +70,7 @@ atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (atomics_cobalt_parser_t *) dc_parser_allocate (context, &atomics_cobalt_parser_vtable);
|
||||
parser = (atomics_cobalt_parser_t *) dc_parser_allocate (context, &atomics_cobalt_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -87,27 +85,6 @@ atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
atomics_cobalt_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
dc_status_t
|
||||
atomics_cobalt_parser_set_calibration (dc_parser_t *abstract, double atmospheric, double hydrostatic)
|
||||
{
|
||||
atomics_cobalt_parser_t *parser = (atomics_cobalt_parser_t*) abstract;
|
||||
|
||||
if (!ISINSTANCE (abstract))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
parser->hydrostatic = hydrostatic;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
atomics_cobalt_parser_set_density (dc_parser_t *abstract, double density)
|
||||
{
|
||||
@ -171,6 +148,7 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
*((unsigned int *) value) = p[0x2a];
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = p[SZ_HEADER + SZ_GASMIX * flags + 5] / 100.0;
|
||||
gasmix->oxygen = p[SZ_HEADER + SZ_GASMIX * flags + 4] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -202,6 +180,7 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
tank->gasmix = flags;
|
||||
tank->beginpressure = array_uint16_le(p + 6) * PSI / BAR;
|
||||
tank->endpressure = array_uint16_le(p + 14) * PSI / BAR;
|
||||
tank->usage = DC_USAGE_NONE;
|
||||
break;
|
||||
case DC_FIELD_DIVEMODE:
|
||||
switch(p[0x24]) {
|
||||
@ -276,19 +255,19 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
|
||||
// Time (seconds).
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/1000 bar).
|
||||
unsigned int depth = array_uint16_le (data + offset + 0);
|
||||
sample.depth = (signed int)(depth - atmospheric) * (BAR / 1000.0) / parser->hydrostatic;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Pressure (1 psi).
|
||||
unsigned int pressure = array_uint16_le (data + offset + 2);
|
||||
sample.pressure.tank = tank;
|
||||
sample.pressure.value = pressure * PSI / BAR;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
|
||||
// Current gas mix
|
||||
unsigned int gasmix = data[offset + 4];
|
||||
@ -304,14 +283,14 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
// Temperature (1 °F).
|
||||
unsigned int temperature = data[offset + 8];
|
||||
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
// violation status
|
||||
sample.event.type = 0;
|
||||
@ -321,15 +300,15 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
unsigned int violation = data[offset + 11];
|
||||
if (violation & 0x01) {
|
||||
sample.event.type = SAMPLE_EVENT_ASCENT;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
if (violation & 0x04) {
|
||||
sample.event.type = SAMPLE_EVENT_CEILING;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
if (violation & 0x08) {
|
||||
sample.event.type = SAMPLE_EVENT_PO2;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
// NDL & deco
|
||||
@ -344,7 +323,8 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.time = ndl;
|
||||
sample.deco.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
|
||||
offset += SZ_SEGMENT;
|
||||
}
|
||||
|
||||
@ -51,7 +51,6 @@
|
||||
#include "context-private.h"
|
||||
#include "iostream-private.h"
|
||||
#include "iterator-private.h"
|
||||
#include "descriptor-private.h"
|
||||
#include "platform.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -455,7 +454,7 @@ dc_bluetooth_iterator_next (dc_iterator_t *abstract, void *out)
|
||||
INFO (abstract->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s",
|
||||
address, name ? name : "");
|
||||
|
||||
if (!dc_descriptor_filter (iterator->descriptor, DC_TRANSPORT_BLUETOOTH, name, NULL)) {
|
||||
if (!dc_descriptor_filter (iterator->descriptor, DC_TRANSPORT_BLUETOOTH, name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -31,6 +31,8 @@
|
||||
|
||||
#define ISINSTANCE(device) dc_device_isinstance((device), &citizen_aqualand_device_vtable)
|
||||
|
||||
#define SZ_HEADER 32
|
||||
|
||||
typedef struct citizen_aqualand_device_t {
|
||||
dc_device_t base;
|
||||
dc_iostream_t *iostream;
|
||||
@ -200,6 +202,12 @@ citizen_aqualand_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
unsigned char *data = dc_buffer_get_data (buffer);
|
||||
unsigned int size = dc_buffer_get_size (buffer);
|
||||
|
||||
if (size < SZ_HEADER) {
|
||||
ERROR (abstract->context, "Dive header is too small (%u).", size);
|
||||
dc_buffer_free (buffer);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
if (callback && memcmp (data + 0x05, device->fingerprint, sizeof (device->fingerprint)) != 0) {
|
||||
callback (data, size, data + 0x05, sizeof (device->fingerprint), userdata);
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
citizen_aqualand_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
citizen_aqualand_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
citizen_aqualand_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -36,7 +36,6 @@ typedef struct citizen_aqualand_parser_t {
|
||||
dc_parser_t base;
|
||||
} citizen_aqualand_parser_t;
|
||||
|
||||
static dc_status_t citizen_aqualand_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t citizen_aqualand_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -44,7 +43,6 @@ static dc_status_t citizen_aqualand_parser_samples_foreach (dc_parser_t *abstrac
|
||||
static const dc_parser_vtable_t citizen_aqualand_parser_vtable = {
|
||||
sizeof(citizen_aqualand_parser_t),
|
||||
DC_FAMILY_CITIZEN_AQUALAND,
|
||||
citizen_aqualand_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -56,7 +54,7 @@ static const dc_parser_vtable_t citizen_aqualand_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
citizen_aqualand_parser_t *parser = NULL;
|
||||
|
||||
@ -64,7 +62,7 @@ citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (citizen_aqualand_parser_t *) dc_parser_allocate (context, &citizen_aqualand_parser_vtable);
|
||||
parser = (citizen_aqualand_parser_t *) dc_parser_allocate (context, &citizen_aqualand_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -76,13 +74,6 @@ citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
citizen_aqualand_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -241,15 +232,15 @@ citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
|
||||
// Time
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth
|
||||
if (metric)
|
||||
sample.depth = depth / 10.0;
|
||||
else
|
||||
sample.depth = depth * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Temperature
|
||||
if (time % 300 == 0) {
|
||||
@ -260,7 +251,7 @@ citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
sample.temperature = temperature / 10.0;
|
||||
else
|
||||
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -603,7 +603,7 @@ cochran_commander_profile_size(cochran_commander_device_t *device, cochran_data_
|
||||
// Corrupt dive, guess the end address
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -965,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 );
|
||||
|
||||
// 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) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
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);
|
||||
|
||||
dc_status_t
|
||||
cochran_commander_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
cochran_commander_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -99,7 +99,6 @@ typedef struct cochran_commander_parser_t {
|
||||
unsigned int nevents;
|
||||
} cochran_commander_parser_t ;
|
||||
|
||||
static dc_status_t cochran_commander_parser_set_data (dc_parser_t *parser, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t cochran_commander_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime);
|
||||
static dc_status_t cochran_commander_parser_get_field (dc_parser_t *parser, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t cochran_commander_parser_samples_foreach (dc_parser_t *parser, dc_sample_callback_t callback, void *userdata);
|
||||
@ -107,7 +106,6 @@ static dc_status_t cochran_commander_parser_samples_foreach (dc_parser_t *parser
|
||||
static const dc_parser_vtable_t cochran_commander_parser_vtable = {
|
||||
sizeof(cochran_commander_parser_t),
|
||||
DC_FAMILY_COCHRAN_COMMANDER,
|
||||
cochran_commander_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -315,7 +313,7 @@ cochran_commander_handle_event (cochran_commander_parser_t *parser, unsigned cha
|
||||
sample.event.time = 0;
|
||||
sample.event.value = 0;
|
||||
sample.event.flags = event->flag;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,7 +350,7 @@ cochran_commander_backparse(cochran_commander_parser_t *parser, const unsigned c
|
||||
|
||||
|
||||
dc_status_t
|
||||
cochran_commander_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
cochran_commander_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
{
|
||||
cochran_commander_parser_t *parser = NULL;
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
@ -361,7 +359,7 @@ cochran_commander_parser_create (dc_parser_t **out, dc_context_t *context, unsig
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (cochran_commander_parser_t *) dc_parser_allocate (context, &cochran_commander_parser_vtable);
|
||||
parser = (cochran_commander_parser_t *) dc_parser_allocate (context, &cochran_commander_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -407,13 +405,6 @@ error_free:
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cochran_commander_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cochran_commander_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -514,6 +505,7 @@ cochran_commander_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
// Gas percentages are decimal and encoded as
|
||||
// highbyte = integer portion
|
||||
// lowbyte = decimal portion, divide by 256 to get decimal value
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->oxygen = array_uint16_le (data + layout->oxygen + 2 * flags) / 256.0 / 100;
|
||||
if (layout->helium == UNSUPPORTED) {
|
||||
gasmix->helium = 0;
|
||||
@ -578,26 +570,26 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
||||
unsigned int temp = samples[0]; // Half degrees F
|
||||
unsigned int depth = samples[1]; // Half feet
|
||||
|
||||
last_sample_time = sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
last_sample_time = sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
sample.depth = (depth / 2.0) * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
sample.temperature = (temp / 2.0 - 32.0) / 1.8;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
sample.gasmix = 0;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
|
||||
while (offset < size) {
|
||||
const unsigned char *s = samples + offset;
|
||||
|
||||
sample.time = time;
|
||||
sample.time = time * 1000;
|
||||
if (last_sample_time != sample.time) {
|
||||
// We haven't issued this time yet.
|
||||
last_sample_time = sample.time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
}
|
||||
|
||||
if (*s & 0x80) {
|
||||
@ -615,7 +607,8 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.time = 60; // We don't know the duration
|
||||
sample.deco.depth = deco_ceiling * FEET;
|
||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||
break;
|
||||
case 0xAD: // Increment ceiling (shallower)
|
||||
deco_ceiling -= 10; // feet
|
||||
@ -623,7 +616,8 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = deco_ceiling * FEET;
|
||||
sample.deco.time = 60; // We don't know the duration
|
||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||
break;
|
||||
default:
|
||||
cochran_commander_handle_event(parser, s[0], callback, userdata);
|
||||
@ -636,7 +630,7 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
||||
else
|
||||
temp += (*s & 0x0f);
|
||||
sample.temperature = (temp / 2.0 - 32.0) / 1.8;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
|
||||
offset++;
|
||||
@ -650,7 +644,7 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
|
||||
depth += s[0] & 0x3f;
|
||||
|
||||
sample.depth = (depth / 2.0) * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
offset++;
|
||||
time += sample_interval;
|
||||
@ -714,27 +708,27 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
start_depth = array_uint16_le (data + layout->start_depth) / 256.0;
|
||||
}
|
||||
|
||||
last_sample_time = sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
last_sample_time = sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
sample.depth = start_depth * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
sample.temperature = (data[layout->start_temp] - 32.0) / 1.8;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
sample.gasmix = 0;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
unsigned int last_gasmix = sample.gasmix;
|
||||
|
||||
while (offset < size) {
|
||||
const unsigned char *s = samples + offset;
|
||||
|
||||
sample.time = time;
|
||||
sample.time = time * 1000;
|
||||
if (last_sample_time != sample.time) {
|
||||
// We haven't issued this time yet.
|
||||
last_sample_time = sample.time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
}
|
||||
|
||||
// If corrupt_dive end before offset
|
||||
@ -774,7 +768,8 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.time = (array_uint16_le(s + 3) + 1) * 60;
|
||||
sample.deco.depth = deco_ceiling * FEET;
|
||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||
break;
|
||||
case 0xAD: // Increment ceiling (shallower)
|
||||
deco_ceiling -= 10; // feet
|
||||
@ -782,7 +777,8 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = deco_ceiling * FEET;
|
||||
sample.deco.time = (array_uint16_le(s + 3) + 1) * 60;
|
||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||
break;
|
||||
case 0xC0: // Switched to FO2 21% mode (surface)
|
||||
// Event seen upon surfacing
|
||||
@ -791,14 +787,14 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
case 0xEF: // Switched to gas blend 2
|
||||
if (last_gasmix != 1) {
|
||||
sample.gasmix = 1;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
last_gasmix = sample.gasmix;
|
||||
}
|
||||
break;
|
||||
case 0xF3: // Switched to gas blend 1
|
||||
if (last_gasmix != 0) {
|
||||
sample.gasmix = 0;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
last_gasmix = sample.gasmix;
|
||||
}
|
||||
break;
|
||||
@ -818,7 +814,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
depth += (s[0] & 0x3f);
|
||||
|
||||
sample.depth = (start_depth + depth / 4.0) * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Ascent rate is logged in the 0th sample, temp in the 1st, repeat.
|
||||
if (time % 2 == 0) {
|
||||
@ -834,7 +830,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
double temperature = s[1] / 2.0 + 20.0;
|
||||
sample.temperature = (temperature - 32.0) / 1.8;
|
||||
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
|
||||
// Cochran EMC models store NDL and deco stop time
|
||||
@ -855,7 +851,8 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.time = deco_time * 60;
|
||||
sample.deco.depth = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
}
|
||||
break;
|
||||
case 23:
|
||||
@ -865,7 +862,8 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = deco_ceiling * FEET;
|
||||
sample.deco.time = deco_time * 60;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -38,6 +38,8 @@
|
||||
#define SZ_PACKET 0x80
|
||||
#define SZ_PAGE (SZ_PACKET / 4)
|
||||
|
||||
#define SZ_HEADER 32
|
||||
|
||||
#define IQ700 0x05
|
||||
#define EDY 0x08
|
||||
|
||||
@ -430,7 +432,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
|
||||
}
|
||||
|
||||
// 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.
|
||||
unsigned int eop = array_uint_le (logbook + layout->config + 2, layout->rb_logbook_size) * SZ_PAGE + layout->rb_profile_begin;
|
||||
@ -455,7 +457,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
|
||||
}
|
||||
|
||||
// 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.
|
||||
if (total + length > layout->rb_profile_end - layout->rb_profile_begin) {
|
||||
@ -479,7 +481,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
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) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
return rc;
|
||||
@ -508,7 +510,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
|
||||
}
|
||||
|
||||
// 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.
|
||||
offset -= length;
|
||||
@ -522,6 +524,13 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (length < SZ_HEADER) {
|
||||
ERROR (abstract->context, "Dive header is too small (%u).", length);
|
||||
dc_rbstream_free (rbstream);
|
||||
free (buffer);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned char *p = buffer + offset;
|
||||
|
||||
if (memcmp (p, device->fingerprint, sizeof (device->fingerprint)) == 0)
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
cressi_edy_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
cressi_edy_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
cressi_edy_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -31,6 +31,8 @@
|
||||
#define IQ700 0x05
|
||||
#define EDY 0x08
|
||||
|
||||
#define SZ_HEADER 32
|
||||
|
||||
typedef struct cressi_edy_parser_t cressi_edy_parser_t;
|
||||
|
||||
struct cressi_edy_parser_t {
|
||||
@ -38,7 +40,6 @@ struct cressi_edy_parser_t {
|
||||
unsigned int model;
|
||||
};
|
||||
|
||||
static dc_status_t cressi_edy_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -46,7 +47,6 @@ static dc_status_t cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_
|
||||
static const dc_parser_vtable_t cressi_edy_parser_vtable = {
|
||||
sizeof(cressi_edy_parser_t),
|
||||
DC_FAMILY_CRESSI_EDY,
|
||||
cressi_edy_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -73,7 +73,7 @@ cressi_edy_parser_count_gasmixes (const unsigned char *data)
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
{
|
||||
cressi_edy_parser_t *parser = NULL;
|
||||
|
||||
@ -81,7 +81,7 @@ cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (cressi_edy_parser_t *) dc_parser_allocate (context, &cressi_edy_parser_vtable);
|
||||
parser = (cressi_edy_parser_t *) dc_parser_allocate (context, &cressi_edy_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -96,17 +96,10 @@ cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cressi_edy_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
if (abstract->size < 32)
|
||||
if (abstract->size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
const unsigned char *p = abstract->data;
|
||||
@ -130,7 +123,7 @@ cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
||||
{
|
||||
cressi_edy_parser_t *parser = (cressi_edy_parser_t *) abstract;
|
||||
|
||||
if (abstract->size < 32)
|
||||
if (abstract->size < SZ_HEADER)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
const unsigned char *p = abstract->data;
|
||||
@ -152,6 +145,7 @@ cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
||||
*((unsigned int *) value) = cressi_edy_parser_count_gasmixes(p);
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->oxygen = bcd2dec (p[0x17 - flags]) / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -188,7 +182,7 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
unsigned int ngasmixes = cressi_edy_parser_count_gasmixes(data);
|
||||
unsigned int gasmix = 0xFFFFFFFF;
|
||||
|
||||
unsigned int offset = 32;
|
||||
unsigned int offset = SZ_HEADER;
|
||||
while (offset + 2 <= size) {
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
@ -201,13 +195,13 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
|
||||
// Time (seconds).
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
unsigned int depth = bcd2dec (data[offset + 0] & 0x0F) * 100 + bcd2dec (data[offset + 1]);
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Current gasmix
|
||||
if (ngasmixes) {
|
||||
@ -220,7 +214,7 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
}
|
||||
if (idx != gasmix) {
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix = idx;
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
cressi_goa_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
cressi_goa_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
cressi_goa_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -62,7 +62,6 @@ typedef struct cressi_goa_layout_t {
|
||||
unsigned int temperature;
|
||||
} cressi_goa_layout_t;
|
||||
|
||||
static dc_status_t cressi_goa_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -70,7 +69,6 @@ static dc_status_t cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_
|
||||
static const dc_parser_vtable_t cressi_goa_parser_vtable = {
|
||||
sizeof(cressi_goa_parser_t),
|
||||
DC_FAMILY_CRESSI_GOA,
|
||||
cressi_goa_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -128,7 +126,7 @@ static const cressi_goa_layout_t layouts[] = {
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
{
|
||||
cressi_goa_parser_t *parser = NULL;
|
||||
|
||||
@ -136,7 +134,7 @@ cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (cressi_goa_parser_t *) dc_parser_allocate (context, &cressi_goa_parser_vtable);
|
||||
parser = (cressi_goa_parser_t *) dc_parser_allocate (context, &cressi_goa_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -149,12 +147,6 @@ cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
cressi_goa_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -250,6 +242,7 @@ cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
||||
*((unsigned int *) value) = ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->oxygen = data[layout->gasmix + 2 * flags + 1] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -329,25 +322,25 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
|
||||
if (complete) {
|
||||
// Time (seconds).
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Temperature (1/10 °C).
|
||||
if (have_temperature) {
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
have_temperature = 0;
|
||||
}
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Gas change
|
||||
if (divemode == SCUBA || divemode == NITROX) {
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
|
||||
#define RB_PROFILE_BEGIN 0x1438
|
||||
#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 PACKETSIZE 32
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
cressi_leonardo_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
cressi_leonardo_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
cressi_leonardo_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -39,7 +39,6 @@ struct cressi_leonardo_parser_t {
|
||||
unsigned int model;
|
||||
};
|
||||
|
||||
static dc_status_t cressi_leonardo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t cressi_leonardo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -47,7 +46,6 @@ static dc_status_t cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract
|
||||
static const dc_parser_vtable_t cressi_leonardo_parser_vtable = {
|
||||
sizeof(cressi_leonardo_parser_t),
|
||||
DC_FAMILY_CRESSI_LEONARDO,
|
||||
cressi_leonardo_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -59,7 +57,7 @@ static const dc_parser_vtable_t cressi_leonardo_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
{
|
||||
cressi_leonardo_parser_t *parser = NULL;
|
||||
|
||||
@ -67,7 +65,7 @@ cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, unsigne
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (cressi_leonardo_parser_t *) dc_parser_allocate (context, &cressi_leonardo_parser_vtable);
|
||||
parser = (cressi_leonardo_parser_t *) dc_parser_allocate (context, &cressi_leonardo_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -81,13 +79,6 @@ cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, unsigne
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cressi_leonardo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -146,6 +137,7 @@ cressi_leonardo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, u
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->oxygen = data[0x19] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -196,12 +188,12 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
|
||||
// Time (seconds).
|
||||
time += surftime;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
offset += 4;
|
||||
} else {
|
||||
@ -211,17 +203,17 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
|
||||
// Time (seconds).
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Gas change.
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
@ -231,7 +223,7 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = ascent;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
offset += 2;
|
||||
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
deepblu_cosmiq_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
deepblu_cosmiq_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
deepblu_cosmiq_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -41,7 +41,6 @@ typedef struct deepblu_cosmiq_parser_t {
|
||||
double hydrostatic;
|
||||
} deepblu_cosmiq_parser_t;
|
||||
|
||||
static dc_status_t deepblu_cosmiq_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t deepblu_cosmiq_parser_set_density (dc_parser_t *abstract, double density);
|
||||
static dc_status_t deepblu_cosmiq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t deepblu_cosmiq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
@ -50,7 +49,6 @@ static dc_status_t deepblu_cosmiq_parser_samples_foreach (dc_parser_t *abstract,
|
||||
static const dc_parser_vtable_t deepblu_cosmiq_parser_vtable = {
|
||||
sizeof(deepblu_cosmiq_parser_t),
|
||||
DC_FAMILY_DEEPBLU_COSMIQ,
|
||||
deepblu_cosmiq_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
deepblu_cosmiq_parser_set_density, /* set_density */
|
||||
@ -61,7 +59,7 @@ static const dc_parser_vtable_t deepblu_cosmiq_parser_vtable = {
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
deepblu_cosmiq_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
deepblu_cosmiq_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
deepblu_cosmiq_parser_t *parser = NULL;
|
||||
|
||||
@ -69,7 +67,7 @@ deepblu_cosmiq_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (deepblu_cosmiq_parser_t *) dc_parser_allocate (context, &deepblu_cosmiq_parser_vtable);
|
||||
parser = (deepblu_cosmiq_parser_t *) dc_parser_allocate (context, &deepblu_cosmiq_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -83,12 +81,6 @@ deepblu_cosmiq_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepblu_cosmiq_parser_set_density (dc_parser_t *abstract, double density)
|
||||
{
|
||||
@ -151,6 +143,7 @@ deepblu_cosmiq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
*((unsigned int *) value) = mode == SCUBA;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->oxygen = data[3] / 100.0;
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -204,14 +197,14 @@ deepblu_cosmiq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
offset += SZ_SAMPLE;
|
||||
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
sample.depth = (signed int) (depth - atmospheric) * (BAR / 1000.0) / parser->hydrostatic;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
deepsix_excursion_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
deepsix_excursion_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
deepsix_excursion_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -112,7 +112,6 @@ typedef struct deepsix_excursion_parser_t {
|
||||
deepsix_excursion_gasmix_t gasmix[MAX_GASMIXES];
|
||||
} deepsix_excursion_parser_t;
|
||||
|
||||
static dc_status_t deepsix_excursion_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t deepsix_excursion_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t deepsix_excursion_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t deepsix_excursion_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -122,7 +121,6 @@ static dc_status_t deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abs
|
||||
static const dc_parser_vtable_t deepsix_parser_vtable = {
|
||||
sizeof(deepsix_excursion_parser_t),
|
||||
DC_FAMILY_DEEPSIX_EXCURSION,
|
||||
deepsix_excursion_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -185,7 +183,7 @@ deepsix_excursion_find_gasmix(deepsix_excursion_parser_t *parser, unsigned int o
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
deepsix_excursion_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
deepsix_excursion_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
deepsix_excursion_parser_t *parser = NULL;
|
||||
|
||||
@ -193,7 +191,7 @@ deepsix_excursion_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (deepsix_excursion_parser_t *) dc_parser_allocate (context, &deepsix_parser_vtable);
|
||||
parser = (deepsix_excursion_parser_t *) dc_parser_allocate (context, &deepsix_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -213,23 +211,6 @@ deepsix_excursion_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
deepsix_excursion_parser_t *parser = (deepsix_excursion_parser_t *) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 0;
|
||||
parser->ngasmixes = 0;
|
||||
for (unsigned int i = 0; i < MAX_GASMIXES; ++i) {
|
||||
parser->gasmix[i].id = 0;
|
||||
parser->gasmix[i].oxygen = 0;
|
||||
parser->gasmix[i].helium = 0;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
deepsix_excursion_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -322,6 +303,7 @@ deepsix_excursion_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
|
||||
gasmix->helium = parser->gasmix[flags].helium / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -423,11 +405,11 @@ deepsix_excursion_parser_samples_foreach_v0 (dc_parser_t *abstract, dc_sample_ca
|
||||
|
||||
if (type == TEMPERATURE) {
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback(DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback(DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
sample.depth = pressure_to_depth(depth, atmospheric, DENSITY);
|
||||
if (callback) callback(DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
}
|
||||
|
||||
if (type == ALARM) {
|
||||
@ -440,11 +422,11 @@ deepsix_excursion_parser_samples_foreach_v0 (dc_parser_t *abstract, dc_sample_ca
|
||||
length = 8;
|
||||
} else if (temperature >= 10) {
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
} else {
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
} else if (type == DECO) {
|
||||
unsigned int deco = array_uint16_le(data + offset + 4);
|
||||
@ -454,7 +436,7 @@ deepsix_excursion_parser_samples_foreach_v0 (dc_parser_t *abstract, dc_sample_ca
|
||||
} else if (type == CNS) {
|
||||
unsigned int cns = array_uint16_le(data + offset + 4);
|
||||
sample.cns = cns / 100.0;
|
||||
if (callback) callback(DC_SAMPLE_CNS, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_CNS, &sample, userdata);
|
||||
}
|
||||
|
||||
offset += length;
|
||||
@ -591,12 +573,12 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca
|
||||
|
||||
// Time (seconds).
|
||||
time += samplerate;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
unsigned int depth = array_uint16_le (data + offset);
|
||||
sample.depth = pressure_to_depth(depth, atmospheric, density);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
offset += 2;
|
||||
|
||||
// event info
|
||||
@ -664,7 +646,7 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca
|
||||
break;
|
||||
}
|
||||
if (sample.event.type != SAMPLE_EVENT_NONE) {
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -686,7 +668,7 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca
|
||||
}
|
||||
|
||||
sample.gasmix = mix_idx;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
break;
|
||||
case EVENT_SAMPLES_MISSED:
|
||||
count = array_uint16_le(data + offset + event_offset);
|
||||
@ -727,12 +709,12 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca
|
||||
case SAMPLE_TEMPERATURE:
|
||||
value = array_uint16_le(data + offset);
|
||||
sample.temperature = value / 10.0;
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
break;
|
||||
case SAMPLE_CNS:
|
||||
value = array_uint16_le(data + offset);
|
||||
sample.cns = value / 10000.0;
|
||||
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata);
|
||||
break;
|
||||
case SAMPLE_DECO_NDL:
|
||||
deco_flags = data[offset];
|
||||
@ -752,7 +734,7 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca
|
||||
sample.deco.depth = 0;
|
||||
sample.deco.time = deco_ndl_tts;
|
||||
}
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
158
src/descriptor.c
158
src/descriptor.c
@ -23,7 +23,10 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "descriptor-private.h"
|
||||
#include <libdivecomputer/descriptor.h>
|
||||
#include <libdivecomputer/usbhid.h>
|
||||
#include <libdivecomputer/usb.h>
|
||||
|
||||
#include "iterator-private.h"
|
||||
#include "platform.h"
|
||||
|
||||
@ -36,36 +39,26 @@
|
||||
values, \
|
||||
C_ARRAY_SIZE(values) - isnullterminated, \
|
||||
C_ARRAY_ITEMSIZE(values), \
|
||||
match, \
|
||||
NULL, NULL, 0)
|
||||
|
||||
#define DC_FILTER_INTERNAL_WITH_PARAMS(key, values, isnullterminated, match, params_dst, params_src) \
|
||||
dc_filter_internal( \
|
||||
key, \
|
||||
values, \
|
||||
C_ARRAY_SIZE(values) - isnullterminated, \
|
||||
C_ARRAY_ITEMSIZE(values), \
|
||||
match, \
|
||||
params_dst, params_src, sizeof *(params_src))
|
||||
match)
|
||||
|
||||
typedef int (*dc_match_t)(const void *, const void *);
|
||||
|
||||
typedef int (*dc_filter_t) (dc_transport_t transport, const void *userdata, void *params);
|
||||
typedef int (*dc_filter_t) (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
|
||||
static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_suunto (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_shearwater (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_hw (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_mares (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_divesystem (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_mclean (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_atomic (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_deepsix (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_deepblu (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_oceans (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_divesoft (dc_transport_t transport, const void *userdata, void *params);
|
||||
static int dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_suunto (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_shearwater (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_hw (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_tecdiving (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_mares (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_divesystem (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_mclean (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_atomic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_deepsix (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_deepblu (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_oceans (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
static int dc_filter_divesoft (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
|
||||
|
||||
static dc_status_t dc_descriptor_iterator_next (dc_iterator_t *iterator, void *item);
|
||||
|
||||
@ -177,7 +170,10 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Scubapro", "G2 TEK", DC_FAMILY_UWATEC_SMART, 0x31, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G2", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G2 Console", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G3", DC_FAMILY_UWATEC_SMART, 0x34, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "G2 HUD", DC_FAMILY_UWATEC_SMART, 0x42, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "Luna 2.0 AI", DC_FAMILY_UWATEC_SMART, 0x50, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
{"Scubapro", "Luna 2.0", DC_FAMILY_UWATEC_SMART, 0x51, DC_TRANSPORT_BLE, dc_filter_uwatec},
|
||||
/* Reefnet */
|
||||
{"Reefnet", "Sensus", DC_FAMILY_REEFNET_SENSUS, 1, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Reefnet", "Sensus Pro", DC_FAMILY_REEFNET_SENSUSPRO, 2, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -276,6 +272,9 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Aqualung", "i470TC", DC_FAMILY_OCEANIC_ATOM2, 0x4743, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "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", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -308,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", "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", "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", "OSTC", DC_FAMILY_HW_OSTC, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Heinrichs Weikamp", "OSTC Mk2", DC_FAMILY_HW_OSTC, 1, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -361,6 +364,7 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Shearwater", "Peregrine", DC_FAMILY_SHEARWATER_PETREL, 9, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Petrel 3", DC_FAMILY_SHEARWATER_PETREL, 10, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Perdix 2", DC_FAMILY_SHEARWATER_PETREL, 11, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
{"Shearwater", "Tern", DC_FAMILY_SHEARWATER_PETREL, 12, DC_TRANSPORT_BLE, dc_filter_shearwater},
|
||||
/* Dive Rite NiTek Q */
|
||||
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
/* Citizen Hyper Aqualand */
|
||||
@ -414,6 +418,20 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Ratio", "iX3M 2021 Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x73, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iX3M 2021 Pro Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x74, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iX3M 2021 Pro Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x75, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Ratio", "iDive 2 Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x80, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Fancy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x81, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x82, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x83, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x84, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Tech", DC_FAMILY_DIVESYSTEM_IDIVE, 0x85, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iDive 2 Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x86, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Gauge", DC_FAMILY_DIVESYSTEM_IDIVE, 0x90, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x91, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x92, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x93, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Tech", DC_FAMILY_DIVESYSTEM_IDIVE, 0x94, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 GPS Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x95, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "ATOM", DC_FAMILY_DIVESYSTEM_IDIVE, 0x96, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Gauge", DC_FAMILY_DIVESYSTEM_IDIVE, 0x100, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x101, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
{"Ratio", "iX3M 2 Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x102, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
|
||||
@ -443,7 +461,6 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Deep Six", "Excursion", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||
{"Crest", "CR-4", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||
{"Genesis", "Centauri", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||
{"Tusa", "TC1", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||
{"Scorpena", "Alpha", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
|
||||
/* Seac Screen */
|
||||
{"Seac", "Screen", DC_FAMILY_SEAC_SCREEN, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -493,6 +510,15 @@ dc_match_usb (const void *key, const void *value)
|
||||
return k->vid == v->vid && k->pid == v->pid;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_match_usbhid (const void *key, const void *value)
|
||||
{
|
||||
const dc_usbhid_desc_t *k = (const dc_usbhid_desc_t *) key;
|
||||
const dc_usbhid_desc_t *v = (const dc_usbhid_desc_t *) value;
|
||||
|
||||
return k->vid == v->vid && k->pid == v->pid;
|
||||
}
|
||||
|
||||
static int
|
||||
dc_match_number_with_prefix (const void *key, const void *value)
|
||||
{
|
||||
@ -533,16 +559,13 @@ dc_match_oceanic (const void *key, const void *value)
|
||||
}
|
||||
|
||||
static int
|
||||
dc_filter_internal (const void *key, const void *values, size_t count, size_t size, dc_match_t match, void *params_dst, const void *params_src, size_t params_size)
|
||||
dc_filter_internal (const void *key, const void *values, size_t count, size_t size, dc_match_t match)
|
||||
{
|
||||
if (key == NULL)
|
||||
return 1;
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
if (match (key, (const unsigned char *) values + i * size)) {
|
||||
if (params_src && params_dst) {
|
||||
memcpy (params_dst, params_src, params_size);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -557,7 +580,8 @@ static const char * const rfcomm[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const irda[] = {
|
||||
"Aladin Smart Com",
|
||||
@ -568,7 +592,7 @@ static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, voi
|
||||
"UWATEC Galileo",
|
||||
"UWATEC Galileo Sol",
|
||||
};
|
||||
static const dc_usb_desc_t usbhid[] = {
|
||||
static const dc_usbhid_desc_t usbhid[] = {
|
||||
{0x2e6c, 0x3201}, // G2, G2 TEK
|
||||
{0x2e6c, 0x3211}, // G2 Console
|
||||
{0x2e6c, 0x4201}, // G2 HUD
|
||||
@ -581,12 +605,15 @@ static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, voi
|
||||
"A1",
|
||||
"A2",
|
||||
"G2 TEK",
|
||||
"Galileo 3",
|
||||
"Luna 2.0 AI",
|
||||
"Luna 2.0",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_IRDA) {
|
||||
return DC_FILTER_INTERNAL (userdata, irda, 0, dc_match_name);
|
||||
} else if (transport == DC_TRANSPORT_USBHID) {
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usb);
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usbhid);
|
||||
} else if (transport == DC_TRANSPORT_BLE) {
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name);
|
||||
}
|
||||
@ -594,9 +621,10 @@ static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, voi
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_suunto (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_suunto (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const dc_usb_desc_t usbhid[] = {
|
||||
static const dc_usbhid_desc_t usbhid[] = {
|
||||
{0x1493, 0x0030}, // Eon Steel
|
||||
{0x1493, 0x0033}, // Eon Core
|
||||
{0x1493, 0x0035}, // D5
|
||||
@ -610,7 +638,7 @@ static int dc_filter_suunto (dc_transport_t transport, const void *userdata, voi
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_USBHID) {
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usb);
|
||||
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usbhid);
|
||||
} else if (transport == DC_TRANSPORT_BLE) {
|
||||
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix);
|
||||
}
|
||||
@ -618,7 +646,8 @@ static int dc_filter_suunto (dc_transport_t transport, const void *userdata, voi
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_hw (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_hw (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"OSTC",
|
||||
@ -634,7 +663,8 @@ static int dc_filter_hw (dc_transport_t transport, const void *userdata, void *p
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_shearwater (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_shearwater (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"Predator",
|
||||
@ -646,6 +676,7 @@ static int dc_filter_shearwater (dc_transport_t transport, const void *userdata,
|
||||
"Perdix 2",
|
||||
"Teric",
|
||||
"Peregrine",
|
||||
"Tern"
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
|
||||
@ -657,7 +688,8 @@ static int dc_filter_shearwater (dc_transport_t transport, const void *userdata,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_tecdiving (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"DiveComputer",
|
||||
@ -672,11 +704,15 @@ static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_mares (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_mares (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"Mares bluelink pro",
|
||||
"Mares Genius",
|
||||
"Sirius",
|
||||
"Quad Ci",
|
||||
"Puck4",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
@ -686,11 +722,13 @@ static int dc_filter_mares (dc_transport_t transport, const void *userdata, void
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_divesystem (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_divesystem (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"DS",
|
||||
"IX5M",
|
||||
"RATIO-",
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
|
||||
@ -700,7 +738,8 @@ static int dc_filter_divesystem (dc_transport_t transport, const void *userdata,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const unsigned int model[] = {
|
||||
0x4552, // Oceanic Pro Plus X
|
||||
@ -714,8 +753,10 @@ static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, vo
|
||||
0x4654, // Oceanic Veo 4.0
|
||||
0x4655, // Sherwood Wisdom 4
|
||||
0x4656, // Oceanic Pro Plus 4
|
||||
0x4741, // Apeks DSX
|
||||
0x4742, // Sherwood Beacon
|
||||
0x4743, // Aqualung i470TC
|
||||
0x4744, // Aqualung i330R
|
||||
0x4749, // Aqualung i200C
|
||||
0x474B, // Oceanic Geo Air
|
||||
};
|
||||
@ -727,7 +768,8 @@ static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, vo
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_mclean(dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_mclean(dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"McLean Extreme",
|
||||
@ -742,30 +784,27 @@ static int dc_filter_mclean(dc_transport_t transport, const void *userdata, void
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_atomic (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_atomic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const dc_usb_desc_t usb[] = {
|
||||
{0x0471, 0x0888}, // Atomic Aquatics Cobalt
|
||||
};
|
||||
|
||||
static const dc_usb_params_t usb_params = {
|
||||
0, 0x82, 0x02
|
||||
};
|
||||
|
||||
if (transport == DC_TRANSPORT_USB) {
|
||||
return DC_FILTER_INTERNAL_WITH_PARAMS (userdata, usb, 0, dc_match_usb, params, &usb_params);
|
||||
return DC_FILTER_INTERNAL (userdata, usb, 0, dc_match_usb);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_deepsix (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_deepsix (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"EXCURSION",
|
||||
"Crest-CR4",
|
||||
"CENTAURI",
|
||||
"TC1",
|
||||
"ALPHA",
|
||||
};
|
||||
|
||||
@ -776,7 +815,8 @@ static int dc_filter_deepsix (dc_transport_t transport, const void *userdata, vo
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_deepblu (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_deepblu (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"COSMIQ",
|
||||
@ -789,7 +829,8 @@ static int dc_filter_deepblu (dc_transport_t transport, const void *userdata, vo
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_oceans (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_oceans (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"S1",
|
||||
@ -802,7 +843,8 @@ static int dc_filter_oceans (dc_transport_t transport, const void *userdata, voi
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dc_filter_divesoft (dc_transport_t transport, const void *userdata, void *params)
|
||||
static int
|
||||
dc_filter_divesoft (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
static const char * const bluetooth[] = {
|
||||
"Freedom",
|
||||
@ -908,10 +950,10 @@ dc_descriptor_get_transports (dc_descriptor_t *descriptor)
|
||||
}
|
||||
|
||||
int
|
||||
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata, void *params)
|
||||
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
|
||||
{
|
||||
if (descriptor == NULL || descriptor->filter == NULL || userdata == NULL)
|
||||
return 1;
|
||||
|
||||
return descriptor->filter (transport, userdata, params);
|
||||
return descriptor->filter (descriptor, transport, userdata);
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
#include "oceanic_atom2.h"
|
||||
#include "oceanic_veo250.h"
|
||||
#include "oceanic_vtpro.h"
|
||||
#include "pelagic_i330r.h"
|
||||
#include "mares_darwin.h"
|
||||
#include "mares_iconhd.h"
|
||||
#include "mares_nemo.h"
|
||||
@ -162,6 +163,9 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
|
||||
case DC_FAMILY_OCEANIC_ATOM2:
|
||||
rc = oceanic_atom2_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
||||
break;
|
||||
case DC_FAMILY_PELAGIC_I330R:
|
||||
rc = pelagic_i330r_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
||||
break;
|
||||
case DC_FAMILY_MARES_NEMO:
|
||||
rc = mares_nemo_device_open (&device, context, iostream);
|
||||
break;
|
||||
@ -172,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));
|
||||
break;
|
||||
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;
|
||||
case DC_FAMILY_HW_OSTC:
|
||||
rc = hw_ostc_device_open (&device, context, iostream);
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
diverite_nitekq_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
diverite_nitekq_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
diverite_nitekq_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -49,7 +49,6 @@ struct diverite_nitekq_parser_t {
|
||||
double maxdepth;
|
||||
};
|
||||
|
||||
static dc_status_t diverite_nitekq_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t diverite_nitekq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -57,7 +56,6 @@ static dc_status_t diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract
|
||||
static const dc_parser_vtable_t diverite_nitekq_parser_vtable = {
|
||||
sizeof(diverite_nitekq_parser_t),
|
||||
DC_FAMILY_DIVERITE_NITEKQ,
|
||||
diverite_nitekq_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -69,7 +67,7 @@ static const dc_parser_vtable_t diverite_nitekq_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
diverite_nitekq_parser_t *parser = NULL;
|
||||
|
||||
@ -77,7 +75,7 @@ diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (diverite_nitekq_parser_t *) dc_parser_allocate (context, &diverite_nitekq_parser_vtable);
|
||||
parser = (diverite_nitekq_parser_t *) dc_parser_allocate (context, &diverite_nitekq_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -101,13 +99,6 @@ diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
diverite_nitekq_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -161,6 +152,7 @@ diverite_nitekq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, u
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = parser->he[flags] / 100.0;
|
||||
gasmix->oxygen = parser->o2[flags] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -264,13 +256,13 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
|
||||
// Time (seconds).
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Gas change
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
@ -282,7 +274,7 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
sample.depth = depth / 10.0;
|
||||
else
|
||||
sample.depth = depth * FEET / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
offset += 2;
|
||||
|
||||
if (type == 3) {
|
||||
@ -293,8 +285,9 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
|
||||
if (offset + 1 > size)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
unsigned int ppo2 = data[offset];
|
||||
sample.ppo2 = ppo2 / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
|
||||
sample.ppo2.sensor = DC_SENSOR_NONE;
|
||||
sample.ppo2.value = ppo2 / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PPO2, &sample, userdata);
|
||||
offset++;
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -35,7 +35,7 @@ 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);
|
||||
divesoft_freedom_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -254,7 +254,6 @@ typedef struct divesoft_freedom_parser_t {
|
||||
unsigned int calibrated;
|
||||
} divesoft_freedom_parser_t;
|
||||
|
||||
static dc_status_t divesoft_freedom_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t divesoft_freedom_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t divesoft_freedom_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -262,7 +261,6 @@ static dc_status_t divesoft_freedom_parser_samples_foreach (dc_parser_t *abstrac
|
||||
static const dc_parser_vtable_t divesoft_freedom_parser_vtable = {
|
||||
sizeof(divesoft_freedom_parser_t),
|
||||
DC_FAMILY_DIVESOFT_FREEDOM,
|
||||
divesoft_freedom_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -643,7 +641,7 @@ divesoft_freedom_cache (divesoft_freedom_parser_t *parser)
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
divesoft_freedom_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
divesoft_freedom_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
divesoft_freedom_parser_t *parser = NULL;
|
||||
|
||||
@ -651,7 +649,7 @@ divesoft_freedom_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (divesoft_freedom_parser_t *) dc_parser_allocate (context, &divesoft_freedom_parser_vtable);
|
||||
parser = (divesoft_freedom_parser_t *) dc_parser_allocate (context, &divesoft_freedom_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -698,50 +696,6 @@ divesoft_freedom_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
divesoft_freedom_parser_t *parser = (divesoft_freedom_parser_t *) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 0;
|
||||
parser->version = 0;
|
||||
parser->headersize = 0;
|
||||
parser->divetime = 0;
|
||||
parser->divemode = 0;
|
||||
parser->temperature_min = 0;
|
||||
parser->maxdepth = 0;
|
||||
parser->atmospheric = 0;
|
||||
parser->avgdepth = 0;
|
||||
parser->ngasmixes = 0;
|
||||
for (unsigned int i = 0; i < NGASMIXES; ++i) {
|
||||
parser->gasmix[i].oxygen = 0;
|
||||
parser->gasmix[i].helium = 0;
|
||||
parser->gasmix[i].type = 0;
|
||||
parser->gasmix[i].id = 0;
|
||||
}
|
||||
parser->diluent = UNDEFINED;
|
||||
parser->ntanks = 0;
|
||||
for (unsigned int i = 0; i < NTANKS; ++i) {
|
||||
parser->tank[i].volume = 0;
|
||||
parser->tank[i].workpressure = 0;
|
||||
parser->tank[i].beginpressure = 0;
|
||||
parser->tank[i].endpressure = 0;
|
||||
parser->tank[i].transmitter = 0;
|
||||
parser->tank[i].active = 0;
|
||||
}
|
||||
parser->vpm = 0;
|
||||
parser->gf_lo = 0;
|
||||
parser->gf_hi = 0;
|
||||
parser->seawater = 0;
|
||||
for (unsigned int i = 0; i < NSENSORS; ++i) {
|
||||
parser->calibration[i] = 0;
|
||||
}
|
||||
parser->calibrated = 0;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
divesoft_freedom_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -755,13 +709,21 @@ divesoft_freedom_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *date
|
||||
return status;
|
||||
|
||||
unsigned int timestamp = array_uint32_le (data + 8);
|
||||
dc_ticks_t ticks = (dc_ticks_t) timestamp + EPOCH;
|
||||
|
||||
int timezone = 0;
|
||||
if (parser->version == HEADER_SIGNATURE_V2) {
|
||||
timezone = ((signed short) array_uint16_le (data + 40)) * 60;
|
||||
} else {
|
||||
timezone = 0;
|
||||
}
|
||||
|
||||
dc_ticks_t ticks = (dc_ticks_t) timestamp + EPOCH + timezone;
|
||||
|
||||
if (!dc_datetime_gmtime (datetime, ticks))
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
|
||||
if (parser->version == HEADER_SIGNATURE_V2) {
|
||||
datetime->timezone = ((signed short) array_uint16_le (data + 40)) * 60;
|
||||
datetime->timezone = timezone;
|
||||
} else {
|
||||
datetime->timezone = DC_TIMEZONE_NONE;
|
||||
}
|
||||
@ -838,6 +800,13 @@ divesoft_freedom_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
if (parser->gasmix[flags].type == OXYGEN) {
|
||||
gasmix->usage = DC_USAGE_OXYGEN;
|
||||
} else if (parser->gasmix[flags].type == DILUENT) {
|
||||
gasmix->usage = DC_USAGE_DILUENT;
|
||||
} else {
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
}
|
||||
gasmix->helium = parser->gasmix[flags].helium / 100.0;
|
||||
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -859,6 +828,7 @@ divesoft_freedom_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
tank->beginpressure = parser->tank[flags].beginpressure * 2.0;
|
||||
tank->endpressure = parser->tank[flags].endpressure * 2.0;
|
||||
tank->gasmix = flags;
|
||||
tank->usage = DC_USAGE_NONE;
|
||||
break;
|
||||
case DC_FIELD_DECOMODEL:
|
||||
if (parser->vpm) {
|
||||
@ -924,15 +894,15 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
continue;
|
||||
}
|
||||
time = timestamp;
|
||||
sample.time = time;
|
||||
if (callback) callback(DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback(DC_SAMPLE_TIME, &sample, userdata);
|
||||
}
|
||||
|
||||
// Initial diluent.
|
||||
if (!initial) {
|
||||
if (parser->diluent != UNDEFINED) {
|
||||
sample.gasmix = parser->diluent;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
}
|
||||
initial = 1;
|
||||
}
|
||||
@ -943,18 +913,19 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
unsigned int ppo2 = array_uint16_le (data + offset + 6);
|
||||
|
||||
sample.depth = depth / 100.0;
|
||||
if (callback) callback(DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
if (ppo2) {
|
||||
sample.ppo2 = ppo2 * 10.0 / BAR;
|
||||
if (callback) callback(DC_SAMPLE_PPO2, sample, userdata);
|
||||
sample.ppo2.sensor = DC_SENSOR_NONE;
|
||||
sample.ppo2.value = ppo2 * 10.0 / BAR;
|
||||
if (callback) callback(DC_SAMPLE_PPO2, &sample, userdata);
|
||||
}
|
||||
|
||||
if (id == POINT_2) {
|
||||
unsigned int orientation = array_uint32_le (data + offset + 8);
|
||||
unsigned int heading = orientation & 0x1FF;
|
||||
sample.bearing = heading;
|
||||
if (callback) callback (DC_SAMPLE_BEARING, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_BEARING, &sample, userdata);
|
||||
} else if (id == POINT_1 || id == POINT_1_OLD) {
|
||||
unsigned int misc = array_uint32_le (data + offset + 8);
|
||||
unsigned int ceiling = array_uint16_le (data + offset + 12);
|
||||
@ -965,7 +936,7 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
|
||||
// Temperature
|
||||
sample.temperature = (signed int) signextend (temp, 10) / 10.0;
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
// Deco / NDL
|
||||
if (ceiling) {
|
||||
@ -977,12 +948,13 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
sample.deco.time = ndl * 60;
|
||||
sample.deco.depth = 0.0;
|
||||
}
|
||||
if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = tts * 60;
|
||||
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
|
||||
|
||||
// Setpoint
|
||||
if (setpoint) {
|
||||
sample.setpoint = setpoint / 100.0;
|
||||
if (callback) callback(DC_SAMPLE_SETPOINT, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||
}
|
||||
}
|
||||
} else if ((type >= LREC_MANIPULATION && type <= LREC_ACTIVITY) || type == LREC_INFO) {
|
||||
@ -994,7 +966,7 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = 0;
|
||||
if (callback) callback(DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_EVENT, &sample, userdata);
|
||||
} else if (event == EVENT_MIX_CHANGED || event == EVENT_DILUENT || event == EVENT_CHANGE_MODE) {
|
||||
unsigned int o2 = data[offset + 6];
|
||||
unsigned int he = data[offset + 7];
|
||||
@ -1014,13 +986,13 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
} else if (event == EVENT_CNS) {
|
||||
sample.cns = array_uint16_le (data + offset + 6) / 100.0;
|
||||
if (callback) callback(DC_SAMPLE_CNS, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_CNS, &sample, userdata);
|
||||
} else if (event == EVENT_SETPOINT_MANUAL || event == EVENT_SETPOINT_AUTO) {
|
||||
sample.setpoint = data[6] / 100.0;
|
||||
if (callback) callback(DC_SAMPLE_SETPOINT, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||
}
|
||||
} else if (type == LREC_MEASURE) {
|
||||
// Measurement record.
|
||||
@ -1038,25 +1010,27 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
|
||||
sample.pressure.tank = idx;
|
||||
sample.pressure.value = pressure * 2.0;
|
||||
if (callback) callback(DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
}
|
||||
} else if (id == MEASURE_ID_OXYGEN) {
|
||||
for (unsigned int i = 0; i < NSENSORS; ++i) {
|
||||
unsigned int ppo2 = array_uint16_le (data + offset + 4 + i * 2);
|
||||
if (ppo2 == 0 || ppo2 == 0xFFFF)
|
||||
continue;
|
||||
sample.ppo2 = ppo2 * 10.0 / BAR;
|
||||
if (callback) callback(DC_SAMPLE_PPO2, sample, userdata);
|
||||
sample.ppo2.sensor = i;
|
||||
sample.ppo2.value = ppo2 * 10.0 / BAR;
|
||||
if (callback) callback(DC_SAMPLE_PPO2, &sample, userdata);
|
||||
}
|
||||
} else if (id == MEASURE_ID_OXYGEN_MV) {
|
||||
for (unsigned int i = 0; i < NSENSORS; ++i) {
|
||||
unsigned int value = array_uint16_le (data + offset + 4 + i * 2);
|
||||
unsigned int state = data[offset + 12 + i];
|
||||
if (!parser->calibrated || state == SENSTAT_UNCALIBRATED ||
|
||||
state == SENSTAT_NOT_EXIST)
|
||||
if (!parser->calibrated || parser->calibration[i] == 0 ||
|
||||
state == SENSTAT_UNCALIBRATED || state == SENSTAT_NOT_EXIST)
|
||||
continue;
|
||||
sample.ppo2 = value / 100.0 * parser->calibration[i] / BAR;
|
||||
if (callback) callback(DC_SAMPLE_PPO2, sample, userdata);
|
||||
sample.ppo2.sensor = i;
|
||||
sample.ppo2.value = value / 100.0 * parser->calibration[i] / BAR;
|
||||
if (callback) callback(DC_SAMPLE_PPO2, &sample, userdata);
|
||||
}
|
||||
}
|
||||
} else if (type == LREC_STATE) {
|
||||
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
divesystem_idive_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
divesystem_idive_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -58,6 +58,9 @@
|
||||
#define IX3M2_ZHL16C 2
|
||||
#define IX3M2_VPM 3
|
||||
|
||||
#define REC_SAMPLE 0
|
||||
#define REC_INFO 1
|
||||
|
||||
typedef struct divesystem_idive_parser_t divesystem_idive_parser_t;
|
||||
|
||||
typedef struct divesystem_idive_gasmix_t {
|
||||
@ -89,7 +92,6 @@ struct divesystem_idive_parser_t {
|
||||
unsigned int gf_high;
|
||||
};
|
||||
|
||||
static dc_status_t divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -97,7 +99,6 @@ static dc_status_t divesystem_idive_parser_samples_foreach (dc_parser_t *abstrac
|
||||
static const dc_parser_vtable_t divesystem_idive_parser_vtable = {
|
||||
sizeof(divesystem_idive_parser_t),
|
||||
DC_FAMILY_DIVESYSTEM_IDIVE,
|
||||
divesystem_idive_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -109,7 +110,7 @@ static const dc_parser_vtable_t divesystem_idive_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
{
|
||||
divesystem_idive_parser_t *parser = NULL;
|
||||
|
||||
@ -117,7 +118,7 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, unsign
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (divesystem_idive_parser_t *) dc_parser_allocate (context, &divesystem_idive_parser_vtable);
|
||||
parser = (divesystem_idive_parser_t *) dc_parser_allocate (context, &divesystem_idive_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -156,35 +157,6 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, unsign
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
divesystem_idive_parser_t *parser = (divesystem_idive_parser_t *) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 0;
|
||||
parser->divemode = INVALID;
|
||||
parser->divetime = 0;
|
||||
parser->maxdepth = 0;
|
||||
parser->ngasmixes = 0;
|
||||
parser->ntanks = 0;
|
||||
for (unsigned int i = 0; i < NGASMIXES; ++i) {
|
||||
parser->gasmix[i].oxygen = 0;
|
||||
parser->gasmix[i].helium = 0;
|
||||
}
|
||||
for (unsigned int i = 0; i < NTANKS; ++i) {
|
||||
parser->tank[i].id = 0;
|
||||
parser->tank[i].beginpressure = 0;
|
||||
parser->tank[i].endpressure = 0;
|
||||
}
|
||||
parser->algorithm = INVALID;
|
||||
parser->gf_low = INVALID;
|
||||
parser->gf_high = INVALID;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -317,6 +289,7 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = parser->gasmix[flags].helium / 100.0;
|
||||
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -331,6 +304,7 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
tank->beginpressure = parser->tank[flags].beginpressure;
|
||||
tank->endpressure = parser->tank[flags].endpressure;
|
||||
tank->gasmix = DC_GASMIX_UNKNOWN;
|
||||
tank->usage = DC_USAGE_NONE;
|
||||
break;
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
if (ISIX3M(parser->model)) {
|
||||
@ -439,6 +413,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
unsigned int algorithm_previous = INVALID;
|
||||
unsigned int gf_low = INVALID;
|
||||
unsigned int gf_high = INVALID;
|
||||
unsigned int have_bearing = 0;
|
||||
|
||||
unsigned int firmware = 0;
|
||||
unsigned int apos4 = 0;
|
||||
@ -467,27 +442,37 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
while (offset + samplesize <= size) {
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
// Get the record type.
|
||||
unsigned int type = ISIX3M(parser->model) ?
|
||||
array_uint16_le (data + offset + 52) :
|
||||
REC_SAMPLE;
|
||||
if (type != REC_SAMPLE) {
|
||||
// Skip non-sample records.
|
||||
offset += samplesize;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Time (seconds).
|
||||
unsigned int timestamp = array_uint32_le (data + offset + 2);
|
||||
if (timestamp <= time) {
|
||||
ERROR (abstract->context, "Timestamp moved backwards.");
|
||||
if (timestamp <= time && time != 0) {
|
||||
ERROR (abstract->context, "Timestamp moved backwards (%u %u).", timestamp, time);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
time = timestamp;
|
||||
sample.time = timestamp;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = timestamp * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
unsigned int depth = array_uint16_le (data + offset + 6);
|
||||
if (maxdepth < depth)
|
||||
maxdepth = depth;
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Temperature (Celsius).
|
||||
signed int temperature = (signed short) array_uint16_le (data + offset + 8);
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
// Dive mode
|
||||
unsigned int mode = data[offset + 18];
|
||||
@ -521,7 +506,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
if (mode == SCR || mode == CCR) {
|
||||
unsigned int setpoint = array_uint16_le (data + offset + 19);
|
||||
sample.setpoint = setpoint / 1000.0;
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||
}
|
||||
|
||||
// Gaschange.
|
||||
@ -548,7 +533,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
}
|
||||
|
||||
sample.gasmix = i;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
o2_previous = o2;
|
||||
he_previous = he;
|
||||
}
|
||||
@ -566,18 +551,20 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
if (decostop) {
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = decostop / 10.0;
|
||||
sample.deco.time = apos4 ? decotime : tts;
|
||||
sample.deco.time = decotime;
|
||||
sample.deco.tts = tts;
|
||||
} else {
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.depth = 0.0;
|
||||
sample.deco.time = tts;
|
||||
sample.deco.tts = 0;
|
||||
}
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
|
||||
// CNS
|
||||
unsigned int cns = array_uint16_le (data + offset + 29);
|
||||
sample.cns = cns / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata);
|
||||
|
||||
// Tank Pressure
|
||||
if (samplesize == SZ_SAMPLE_IX3M_APOS4) {
|
||||
@ -598,7 +585,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = 0;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
} else {
|
||||
// Get the index of the tank.
|
||||
if (id != tank_previous) {
|
||||
@ -628,10 +615,20 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
if (tank_idx < ntanks) {
|
||||
sample.pressure.tank = tank_idx;
|
||||
sample.pressure.value = pressure;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
tank[tank_idx].endpressure = pressure;
|
||||
}
|
||||
}
|
||||
|
||||
// Compass bearing
|
||||
unsigned int bearing = array_uint16_le (data + offset + 50);
|
||||
if (bearing != 0) {
|
||||
have_bearing = 1; // Stop ignoring zero values.
|
||||
}
|
||||
if (have_bearing && bearing != 0xFFFF) {
|
||||
sample.bearing = bearing;
|
||||
if (callback) callback (DC_SAMPLE_BEARING, &sample, userdata);
|
||||
}
|
||||
}
|
||||
|
||||
offset += samplesize;
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
|
||||
#define RB_PROFILE_BEGIN 0x000000
|
||||
#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 HEADER 0x61
|
||||
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
hw_ostc_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -1715,6 +1715,10 @@ hw_ostc3_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (device->hardware == OSTC4) {
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.firmware = device->firmware;
|
||||
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
hw_ostc3_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int 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
|
||||
}
|
||||
|
||||
@ -37,10 +37,6 @@
|
||||
|
||||
#define UNDEFINED 0xFFFFFFFF
|
||||
|
||||
#define ALL 0
|
||||
#define FIXED 1
|
||||
#define MANUAL 2
|
||||
|
||||
#define HEADER 1
|
||||
#define PROFILE 2
|
||||
|
||||
@ -108,10 +104,12 @@ typedef struct hw_ostc_layout_t {
|
||||
} hw_ostc_layout_t;
|
||||
|
||||
typedef struct hw_ostc_gasmix_t {
|
||||
unsigned int id;
|
||||
unsigned int oxygen;
|
||||
unsigned int helium;
|
||||
unsigned int type;
|
||||
unsigned int enabled;
|
||||
unsigned int active;
|
||||
unsigned int diluent;
|
||||
} hw_ostc_gasmix_t;
|
||||
|
||||
@ -126,21 +124,22 @@ typedef struct hw_ostc_parser_t {
|
||||
const hw_ostc_layout_t *layout;
|
||||
unsigned int ngasmixes;
|
||||
unsigned int nfixed;
|
||||
unsigned int ndisabled;
|
||||
unsigned int initial;
|
||||
unsigned int initial_setpoint;
|
||||
unsigned int initial_cns;
|
||||
hw_ostc_gasmix_t gasmix[NGASMIXES];
|
||||
} hw_ostc_parser_t;
|
||||
|
||||
static dc_status_t hw_ostc_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
|
||||
static dc_status_t hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t callback, void *userdata);
|
||||
|
||||
static const dc_parser_vtable_t hw_ostc_parser_vtable = {
|
||||
sizeof(hw_ostc_parser_t),
|
||||
DC_FAMILY_HW_OSTC,
|
||||
hw_ostc_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -196,15 +195,10 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc3 = {
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
hw_ostc_find_gasmix (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he, unsigned int dil, unsigned int type)
|
||||
hw_ostc_find_gasmix_manual (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he, unsigned int dil)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
unsigned int offset = parser->nfixed - parser->ndisabled;
|
||||
unsigned int count = parser->ngasmixes;
|
||||
if (type == FIXED) {
|
||||
count = parser->nfixed;
|
||||
} else if (type == MANUAL) {
|
||||
offset = parser->nfixed;
|
||||
}
|
||||
|
||||
unsigned int i = offset;
|
||||
while (i < count) {
|
||||
@ -216,6 +210,22 @@ hw_ostc_find_gasmix (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he,
|
||||
return i;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
hw_ostc_find_gasmix_fixed (hw_ostc_parser_t *parser, unsigned int id)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
unsigned int count = parser->nfixed - parser->ndisabled;
|
||||
|
||||
unsigned int i = offset;
|
||||
while (i < count) {
|
||||
if (id == parser->gasmix[i].id)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
hw_ostc_is_ccr (unsigned int divemode, unsigned int version)
|
||||
{
|
||||
@ -297,19 +307,23 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
||||
initial = data[31];
|
||||
}
|
||||
for (unsigned int i = 0; i < ngasmixes; ++i) {
|
||||
gasmix[i].id = i + 1;
|
||||
gasmix[i].oxygen = data[25 + 2 * i];
|
||||
gasmix[i].helium = 0;
|
||||
gasmix[i].type = 0;
|
||||
gasmix[i].enabled = 1;
|
||||
gasmix[i].active = 0;
|
||||
gasmix[i].diluent = 0;
|
||||
}
|
||||
} else if (version == 0x23 || version == 0x24) {
|
||||
ngasmixes = 5;
|
||||
for (unsigned int i = 0; i < ngasmixes; ++i) {
|
||||
gasmix[i].id = i + 1;
|
||||
gasmix[i].oxygen = data[28 + 4 * i + 0];
|
||||
gasmix[i].helium = data[28 + 4 * i + 1];
|
||||
gasmix[i].type = data[28 + 4 * i + 3];
|
||||
gasmix[i].enabled = gasmix[i].type != 0;
|
||||
gasmix[i].active = 0;
|
||||
gasmix[i].diluent = ccr;
|
||||
// Find the first gas marked as the initial gas.
|
||||
if (initial == UNDEFINED && data[28 + 4 * i + 3] == 1) {
|
||||
@ -328,6 +342,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
||||
initial = data[31];
|
||||
}
|
||||
for (unsigned int i = 0; i < ngasmixes; ++i) {
|
||||
gasmix[i].id = i + 1;
|
||||
gasmix[i].oxygen = data[19 + 2 * i + 0];
|
||||
gasmix[i].helium = data[19 + 2 * i + 1];
|
||||
gasmix[i].type = 0;
|
||||
@ -336,6 +351,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
||||
} else {
|
||||
gasmix[i].enabled = 1;
|
||||
}
|
||||
gasmix[i].active = 0;
|
||||
gasmix[i].diluent = ccr;
|
||||
}
|
||||
}
|
||||
@ -344,7 +360,6 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
||||
ERROR(abstract->context, "Invalid initial gas mix.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
initial--; /* Convert to a zero based index. */
|
||||
} else {
|
||||
WARNING(abstract->context, "No initial gas mix available.");
|
||||
}
|
||||
@ -355,6 +370,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
||||
parser->layout = layout;
|
||||
parser->ngasmixes = ngasmixes;
|
||||
parser->nfixed = ngasmixes;
|
||||
parser->ndisabled = 0;
|
||||
parser->initial = initial;
|
||||
parser->initial_setpoint = initial_setpoint;
|
||||
parser->initial_cns = initial_cns;
|
||||
@ -367,7 +383,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsigned int 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;
|
||||
|
||||
@ -375,7 +391,7 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (hw_ostc_parser_t *) dc_parser_allocate (context, &hw_ostc_parser_vtable);
|
||||
parser = (hw_ostc_parser_t *) dc_parser_allocate (context, &hw_ostc_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -390,14 +406,17 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign
|
||||
parser->layout = NULL;
|
||||
parser->ngasmixes = 0;
|
||||
parser->nfixed = 0;
|
||||
parser->ndisabled = 0;
|
||||
parser->initial = 0;
|
||||
parser->initial_setpoint = 0;
|
||||
parser->initial_cns = 0;
|
||||
for (unsigned int i = 0; i < NGASMIXES; ++i) {
|
||||
parser->gasmix[i].id = 0;
|
||||
parser->gasmix[i].oxygen = 0;
|
||||
parser->gasmix[i].helium = 0;
|
||||
parser->gasmix[i].type = 0;
|
||||
parser->gasmix[i].enabled = 0;
|
||||
parser->gasmix[i].active = 0;
|
||||
parser->gasmix[i].diluent = 0;
|
||||
}
|
||||
|
||||
@ -408,44 +427,17 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign
|
||||
|
||||
|
||||
dc_status_t
|
||||
hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
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
|
||||
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;
|
||||
parser->gasmix[i].type = 0;
|
||||
parser->gasmix[i].enabled = 0;
|
||||
parser->gasmix[i].diluent = 0;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -519,7 +511,7 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
||||
|
||||
// Cache the profile data.
|
||||
if (parser->cached < PROFILE) {
|
||||
rc = hw_ostc_parser_samples_foreach (abstract, NULL, NULL);
|
||||
rc = hw_ostc_parser_internal_foreach (parser, NULL, NULL);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
}
|
||||
@ -552,6 +544,8 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
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->helium = parser->gasmix[flags].helium / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -705,17 +699,12 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
||||
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
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;
|
||||
unsigned int size = abstract->size;
|
||||
|
||||
// Cache the parser data.
|
||||
dc_status_t rc = hw_ostc_parser_cache (parser);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
unsigned int version = parser->version;
|
||||
unsigned int header = parser->header;
|
||||
const hw_ostc_layout_t *layout = parser->layout;
|
||||
@ -821,7 +810,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
|
||||
unsigned int time = 0;
|
||||
unsigned int nsamples = 0;
|
||||
unsigned int tank = parser->initial != UNDEFINED ? parser->initial : 0;
|
||||
unsigned int tank = parser->initial != UNDEFINED ? parser->initial - 1 : 0;
|
||||
|
||||
unsigned int offset = header;
|
||||
if (version == 0x23 || version == 0x24)
|
||||
@ -833,31 +822,33 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
|
||||
// Time (seconds).
|
||||
time += samplerate;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Initial gas mix.
|
||||
if (time == samplerate && parser->initial != UNDEFINED) {
|
||||
sample.gasmix = parser->initial;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
unsigned int idx = hw_ostc_find_gasmix_fixed (parser, parser->initial);
|
||||
parser->gasmix[idx].active = 1;
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
}
|
||||
|
||||
// Initial setpoint (mbar).
|
||||
if (time == samplerate && parser->initial_setpoint != UNDEFINED) {
|
||||
sample.setpoint = parser->initial_setpoint / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||
}
|
||||
|
||||
// Initial CNS (%).
|
||||
if (time == samplerate && parser->initial_cns != UNDEFINED) {
|
||||
sample.cns = parser->initial_cns / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata);
|
||||
}
|
||||
|
||||
// Depth (1/100 m).
|
||||
unsigned int depth = array_uint16_le (data + offset);
|
||||
sample.depth = depth / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
offset += 2;
|
||||
|
||||
// Extended sample info.
|
||||
@ -916,7 +907,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
break;
|
||||
}
|
||||
if (sample.event.type && callback)
|
||||
callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
|
||||
// Manual Gas Set & Change
|
||||
if (events & 0x10) {
|
||||
@ -926,22 +917,24 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
}
|
||||
unsigned int o2 = data[offset];
|
||||
unsigned int he = data[offset + 1];
|
||||
unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, ccr, MANUAL);
|
||||
unsigned int idx = hw_ostc_find_gasmix_manual (parser, o2, he, ccr);
|
||||
if (idx >= parser->ngasmixes) {
|
||||
if (idx >= NGASMIXES) {
|
||||
ERROR (abstract->context, "Maximum number of gas mixes reached.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
parser->gasmix[idx].id = 0;
|
||||
parser->gasmix[idx].oxygen = o2;
|
||||
parser->gasmix[idx].helium = he;
|
||||
parser->gasmix[idx].type = 0;
|
||||
parser->gasmix[idx].enabled = 1;
|
||||
parser->gasmix[idx].active = 1;
|
||||
parser->gasmix[idx].diluent = ccr;
|
||||
parser->ngasmixes = idx + 1;
|
||||
}
|
||||
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
offset += 2;
|
||||
length -= 2;
|
||||
}
|
||||
@ -952,19 +945,20 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
unsigned int idx = data[offset];
|
||||
if (parser->model == OSTC4 && ccr && idx > parser->nfixed) {
|
||||
unsigned int id = data[offset];
|
||||
if (parser->model == OSTC4 && ccr && id > parser->nfixed) {
|
||||
// Fix the OSTC4 diluent index.
|
||||
idx -= parser->nfixed;
|
||||
id -= parser->nfixed;
|
||||
}
|
||||
if (idx < 1 || idx > parser->nfixed) {
|
||||
ERROR(abstract->context, "Invalid gas mix (%u).", idx);
|
||||
if (id < 1 || id > parser->nfixed) {
|
||||
ERROR(abstract->context, "Invalid gas mix (%u).", id);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
idx--; /* Convert to a zero based index. */
|
||||
unsigned int idx = hw_ostc_find_gasmix_fixed (parser, id);
|
||||
parser->gasmix[idx].active = 1;
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
tank = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
tank = id - 1;
|
||||
offset++;
|
||||
length--;
|
||||
}
|
||||
@ -977,7 +971,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
sample.setpoint = data[offset] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||
offset++;
|
||||
length--;
|
||||
}
|
||||
@ -991,22 +985,24 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
|
||||
unsigned int o2 = data[offset];
|
||||
unsigned int he = data[offset + 1];
|
||||
unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, 0, MANUAL);
|
||||
unsigned int idx = hw_ostc_find_gasmix_manual (parser, o2, he, 0);
|
||||
if (idx >= parser->ngasmixes) {
|
||||
if (idx >= NGASMIXES) {
|
||||
ERROR (abstract->context, "Maximum number of gas mixes reached.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
parser->gasmix[idx].id = 0;
|
||||
parser->gasmix[idx].oxygen = o2;
|
||||
parser->gasmix[idx].helium = he;
|
||||
parser->gasmix[idx].type = 0;
|
||||
parser->gasmix[idx].enabled = 1;
|
||||
parser->gasmix[idx].active = 1;
|
||||
parser->gasmix[idx].diluent = 0;
|
||||
parser->ngasmixes = idx + 1;
|
||||
}
|
||||
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
offset += 2;
|
||||
length -= 2;
|
||||
}
|
||||
@ -1038,7 +1034,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
case TEMPERATURE:
|
||||
value = array_uint16_le (data + offset);
|
||||
sample.temperature = value / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
break;
|
||||
case DECO:
|
||||
// Due to a firmware bug, the deco/ndl info is incorrect for
|
||||
@ -1053,7 +1049,8 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
sample.deco.depth = 0.0;
|
||||
}
|
||||
sample.deco.time = data[offset + 1] * 60;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
break;
|
||||
case PPO2:
|
||||
for (unsigned int j = 0; j < 3; ++j) {
|
||||
@ -1067,8 +1064,9 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
}
|
||||
if (count) {
|
||||
for (unsigned int j = 0; j < 3; ++j) {
|
||||
sample.ppo2 = ppo2[j] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
|
||||
sample.ppo2.sensor = i;
|
||||
sample.ppo2.value = ppo2[j] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PPO2, &sample, userdata);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1077,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;
|
||||
else
|
||||
sample.cns = data[offset] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata);
|
||||
break;
|
||||
case TANK:
|
||||
value = array_uint16_le (data + offset);
|
||||
@ -1090,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))) {
|
||||
sample.pressure.value /= 10.0;
|
||||
}
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
}
|
||||
break;
|
||||
default: // Not yet used.
|
||||
@ -1110,7 +1108,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
sample.setpoint = data[offset] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||
offset++;
|
||||
length--;
|
||||
}
|
||||
@ -1124,22 +1122,24 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
|
||||
unsigned int o2 = data[offset];
|
||||
unsigned int he = data[offset + 1];
|
||||
unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, 0, MANUAL);
|
||||
unsigned int idx = hw_ostc_find_gasmix_manual (parser, o2, he, 0);
|
||||
if (idx >= parser->ngasmixes) {
|
||||
if (idx >= NGASMIXES) {
|
||||
ERROR (abstract->context, "Maximum number of gas mixes reached.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
parser->gasmix[idx].id = 0;
|
||||
parser->gasmix[idx].oxygen = o2;
|
||||
parser->gasmix[idx].helium = he;
|
||||
parser->gasmix[idx].type = 0;
|
||||
parser->gasmix[idx].enabled = 1;
|
||||
parser->gasmix[idx].active = 1;
|
||||
parser->gasmix[idx].diluent = 0;
|
||||
parser->ngasmixes = idx + 1;
|
||||
}
|
||||
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
offset += 2;
|
||||
length -= 2;
|
||||
}
|
||||
@ -1157,7 +1157,50 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Remove the disabled gas mixes from the fixed gas mixes.
|
||||
unsigned int ndisabled = 0, nenabled = 0;
|
||||
unsigned int count = parser->nfixed - parser->ndisabled;
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
if (parser->gasmix[i].enabled || parser->gasmix[i].active) {
|
||||
// Move the fixed gas mix.
|
||||
parser->gasmix[nenabled] = parser->gasmix[i];
|
||||
nenabled++;
|
||||
} else {
|
||||
ndisabled++;
|
||||
}
|
||||
}
|
||||
|
||||
// Move all the manual gas mixes.
|
||||
memmove (parser->gasmix + nenabled, parser->gasmix + count,
|
||||
(parser->ngasmixes - count) * sizeof (hw_ostc_gasmix_t));
|
||||
memset (parser->gasmix + parser->ngasmixes - ndisabled, 0,
|
||||
ndisabled * sizeof (hw_ostc_gasmix_t));
|
||||
|
||||
// Adjust the counts.
|
||||
parser->ngasmixes -= ndisabled;
|
||||
parser->ndisabled += ndisabled;
|
||||
|
||||
parser->cached = PROFILE;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
hw_ostc_parser_t *parser = (hw_ostc_parser_t *) abstract;
|
||||
|
||||
// Cache the header data.
|
||||
dc_status_t rc = hw_ostc_parser_cache (parser);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
// Cache the profile data.
|
||||
if (parser->cached < PROFILE) {
|
||||
rc = hw_ostc_parser_internal_foreach (parser, NULL, NULL);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return hw_ostc_parser_internal_foreach (parser, callback, userdata);
|
||||
}
|
||||
|
||||
@ -47,7 +47,6 @@
|
||||
#include "context-private.h"
|
||||
#include "iostream-private.h"
|
||||
#include "iterator-private.h"
|
||||
#include "descriptor-private.h"
|
||||
#include "array.h"
|
||||
#include "platform.h"
|
||||
|
||||
@ -226,7 +225,7 @@ dc_irda_iterator_new (dc_iterator_t **out, dc_context_t *context, dc_descriptor_
|
||||
INFO (context, "Discover: address=%08x, name=%s, charset=%02x, hints=%04x",
|
||||
address, name, charset, hints);
|
||||
|
||||
if (!dc_descriptor_filter (descriptor, DC_TRANSPORT_IRDA, name, NULL)) {
|
||||
if (!dc_descriptor_filter (descriptor, DC_TRANSPORT_IRDA, name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -34,6 +34,7 @@ dc_descriptor_get_product
|
||||
dc_descriptor_get_type
|
||||
dc_descriptor_get_model
|
||||
dc_descriptor_get_transports
|
||||
dc_descriptor_filter
|
||||
|
||||
dc_iostream_get_transport
|
||||
dc_iostream_set_timeout
|
||||
@ -91,17 +92,11 @@ dc_parser_set_clock
|
||||
dc_parser_set_atmospheric
|
||||
dc_parser_set_density
|
||||
dc_parser_get_type
|
||||
dc_parser_set_data
|
||||
dc_parser_get_datetime
|
||||
dc_parser_get_field
|
||||
dc_parser_samples_foreach
|
||||
dc_parser_destroy
|
||||
|
||||
reefnet_sensus_parser_set_calibration
|
||||
reefnet_sensuspro_parser_set_calibration
|
||||
reefnet_sensusultra_parser_set_calibration
|
||||
atomics_cobalt_parser_set_calibration
|
||||
|
||||
dc_device_open
|
||||
dc_device_close
|
||||
dc_device_dump
|
||||
|
||||
@ -67,12 +67,12 @@
|
||||
#define RB_LOGBOOK_BEGIN (1 * PAGESIZE)
|
||||
#define RB_LOGBOOK_END (25 * PAGESIZE)
|
||||
#define RB_LOGBOOK_SIZE (RB_LOGBOOK_END - RB_LOGBOOK_BEGIN)
|
||||
#define RB_LOGBOOK_DISTANCE(a,b) ringbuffer_distance (a, b, 1, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END)
|
||||
#define RB_LOGBOOK_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_FULL, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END)
|
||||
|
||||
#define RB_PROFILE_BEGIN (25 * PAGESIZE)
|
||||
#define RB_PROFILE_END (500 * PAGESIZE)
|
||||
#define RB_PROFILE_SIZE (RB_PROFILE_END - RB_PROFILE_BEGIN)
|
||||
#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, 1, RB_PROFILE_BEGIN, RB_PROFILE_END)
|
||||
#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_FULL, RB_PROFILE_BEGIN, RB_PROFILE_END)
|
||||
|
||||
#define SZ_HEADER_XEN 80
|
||||
#define SZ_HEADER_OTHER 96
|
||||
@ -469,7 +469,7 @@ liquivision_lynx_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
dc_rbstream_t *rblogbook = NULL;
|
||||
status = dc_rbstream_new (&rblogbook, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END, rb_logbook_end);
|
||||
status = dc_rbstream_new (&rblogbook, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END, rb_logbook_end, DC_RBSTREAM_BACKWARD);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
goto error_free_logbook;
|
||||
@ -600,7 +600,7 @@ liquivision_lynx_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
dc_rbstream_t *rbprofile = NULL;
|
||||
status = dc_rbstream_new (&rbprofile, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_PROFILE_BEGIN, RB_PROFILE_END, rb_profile_end);
|
||||
status = dc_rbstream_new (&rbprofile, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_PROFILE_BEGIN, RB_PROFILE_END, rb_profile_end, DC_RBSTREAM_BACKWARD);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
goto error_free_profile;
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
liquivision_lynx_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
liquivision_lynx_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
liquivision_lynx_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -117,7 +117,6 @@ struct liquivision_lynx_parser_t {
|
||||
liquivision_lynx_tank_t tank[NTANKS];
|
||||
};
|
||||
|
||||
static dc_status_t liquivision_lynx_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t liquivision_lynx_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t liquivision_lynx_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t liquivision_lynx_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -125,7 +124,6 @@ static dc_status_t liquivision_lynx_parser_samples_foreach (dc_parser_t *abstrac
|
||||
static const dc_parser_vtable_t liquivision_lynx_parser_vtable = {
|
||||
sizeof(liquivision_lynx_parser_t),
|
||||
DC_FAMILY_LIQUIVISION_LYNX,
|
||||
liquivision_lynx_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -137,7 +135,7 @@ static const dc_parser_vtable_t liquivision_lynx_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
liquivision_lynx_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
liquivision_lynx_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
{
|
||||
liquivision_lynx_parser_t *parser = NULL;
|
||||
|
||||
@ -145,7 +143,7 @@ liquivision_lynx_parser_create (dc_parser_t **out, dc_context_t *context, unsign
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (liquivision_lynx_parser_t *) dc_parser_allocate (context, &liquivision_lynx_parser_vtable);
|
||||
parser = (liquivision_lynx_parser_t *) dc_parser_allocate (context, &liquivision_lynx_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -173,29 +171,6 @@ liquivision_lynx_parser_create (dc_parser_t **out, dc_context_t *context, unsign
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
liquivision_lynx_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
liquivision_lynx_parser_t *parser = (liquivision_lynx_parser_t *) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 0;
|
||||
parser->ngasmixes = 0;
|
||||
parser->ntanks = 0;
|
||||
for (unsigned int i = 0; i < NGASMIXES; ++i) {
|
||||
parser->gasmix[i].oxygen = 0;
|
||||
parser->gasmix[i].helium = 0;
|
||||
}
|
||||
for (unsigned int i = 0; i < NTANKS; ++i) {
|
||||
parser->tank[i].id = 0;
|
||||
parser->tank[i].beginpressure = 0;
|
||||
parser->tank[i].endpressure = 0;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
liquivision_lynx_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -315,6 +290,7 @@ liquivision_lynx_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = parser->gasmix[flags].helium / 100.0;
|
||||
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -329,6 +305,7 @@ liquivision_lynx_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
|
||||
tank->beginpressure = parser->tank[flags].beginpressure / 100.0;
|
||||
tank->endpressure = parser->tank[flags].endpressure / 100.0;
|
||||
tank->gasmix = DC_GASMIX_UNKNOWN;
|
||||
tank->usage = DC_USAGE_NONE;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
@ -545,29 +522,29 @@ liquivision_lynx_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
|
||||
// Time (seconds).
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/100 m).
|
||||
sample.depth = value / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Temperature (1/10 °C).
|
||||
int temperature = (signed short) array_uint16_le (data + offset);
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
// Gas mix
|
||||
if (have_gasmix) {
|
||||
sample.gasmix = gasmix_idx;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
have_gasmix = 0;
|
||||
}
|
||||
|
||||
// Setpoint (1/10 bar).
|
||||
if (have_setpoint) {
|
||||
sample.setpoint = setpoint / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||
have_setpoint = 0;
|
||||
}
|
||||
|
||||
@ -577,7 +554,7 @@ liquivision_lynx_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
if (have_pressure & (1 << i)) {
|
||||
sample.pressure.tank = i;
|
||||
sample.pressure.value = pressure[i] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
}
|
||||
}
|
||||
have_pressure = 0;
|
||||
@ -593,7 +570,8 @@ liquivision_lynx_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
|
||||
sample.deco.depth = 0.0;
|
||||
}
|
||||
sample.deco.time = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
have_deco = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
mares_darwin_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
|
||||
|
||||
dc_status_t
|
||||
mares_darwin_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
mares_darwin_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -47,7 +47,6 @@ struct mares_darwin_parser_t {
|
||||
unsigned int samplesize;
|
||||
};
|
||||
|
||||
static dc_status_t mares_darwin_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t mares_darwin_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t mares_darwin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -55,7 +54,6 @@ static dc_status_t mares_darwin_parser_samples_foreach (dc_parser_t *abstract, d
|
||||
static const dc_parser_vtable_t mares_darwin_parser_vtable = {
|
||||
sizeof(mares_darwin_parser_t),
|
||||
DC_FAMILY_MARES_DARWIN,
|
||||
mares_darwin_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -67,7 +65,7 @@ static const dc_parser_vtable_t mares_darwin_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
mares_darwin_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
mares_darwin_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
{
|
||||
mares_darwin_parser_t *parser = NULL;
|
||||
|
||||
@ -75,7 +73,7 @@ mares_darwin_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (mares_darwin_parser_t *) dc_parser_allocate (context, &mares_darwin_parser_vtable);
|
||||
parser = (mares_darwin_parser_t *) dc_parser_allocate (context, &mares_darwin_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -97,13 +95,6 @@ mares_darwin_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
mares_darwin_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
mares_darwin_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -159,6 +150,7 @@ mares_darwin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.0;
|
||||
if (mode == NITROX) {
|
||||
gasmix->oxygen = p[0x0E] / 100.0;
|
||||
@ -185,6 +177,7 @@ mares_darwin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
|
||||
tank->gasmix = 0;
|
||||
tank->beginpressure = array_uint16_be (p + 0x17);
|
||||
tank->endpressure = array_uint16_be (p + 0x19);
|
||||
tank->usage = DC_USAGE_NONE;
|
||||
} else {
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
@ -242,17 +235,17 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
|
||||
// Surface Time (seconds).
|
||||
time += 20;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Gas change.
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
@ -262,7 +255,7 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = ascent;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
// Deco violation
|
||||
@ -271,7 +264,7 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = 0;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
// Deco stop
|
||||
@ -282,7 +275,8 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
}
|
||||
sample.deco.time = 0;
|
||||
sample.deco.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
|
||||
if (parser->samplesize == 3) {
|
||||
unsigned int type = (time / 20 + 2) % 3;
|
||||
@ -291,7 +285,7 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
pressure -= abstract->data[offset + 2];
|
||||
sample.pressure.tank = 0;
|
||||
sample.pressure.value = pressure;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,7 +21,6 @@
|
||||
|
||||
#include <string.h> // memcpy, memcmp
|
||||
#include <stdlib.h> // malloc, free
|
||||
#include <assert.h> // assert
|
||||
|
||||
#include "mares_iconhd.h"
|
||||
#include "context-private.h"
|
||||
@ -49,11 +48,39 @@
|
||||
#define SMARTAIR 0x24
|
||||
#define QUAD 0x29
|
||||
#define HORIZON 0x2C
|
||||
#define PUCKAIR2 0x2D
|
||||
#define SIRIUS 0x2F
|
||||
#define QUADCI 0x31
|
||||
#define PUCK4 0x35
|
||||
|
||||
#define ISSMART(model) ( \
|
||||
(model) == SMART || \
|
||||
(model) == SMARTAPNEA || \
|
||||
(model) == SMARTAIR)
|
||||
|
||||
#define ISGENIUS(model) ( \
|
||||
(model) == GENIUS || \
|
||||
(model) == HORIZON || \
|
||||
(model) == PUCKAIR2 || \
|
||||
(model) == SIRIUS || \
|
||||
(model) == QUADCI || \
|
||||
(model) == PUCK4)
|
||||
|
||||
#define ISSIRIUS(model) ( \
|
||||
(model) == PUCKAIR2 || \
|
||||
(model) == SIRIUS || \
|
||||
(model) == QUADCI || \
|
||||
(model) == PUCK4)
|
||||
|
||||
#define MAXRETRIES 4
|
||||
|
||||
#define MAXPACKET 244
|
||||
|
||||
#define FIXED 0
|
||||
#define VARIABLE 1
|
||||
|
||||
#define ACK 0xAA
|
||||
#define EOF 0xEA
|
||||
#define END 0xEA
|
||||
#define XOR 0xA5
|
||||
|
||||
#define CMD_VERSION 0xC2
|
||||
@ -63,6 +90,8 @@
|
||||
#define CMD_OBJ_EVEN 0xAC
|
||||
#define CMD_OBJ_ODD 0xFE
|
||||
|
||||
#define OBJ_DEVICE 0x2000
|
||||
#define OBJ_DEVICE_SERIAL 0x04
|
||||
#define OBJ_LOGBOOK 0x2008
|
||||
#define OBJ_LOGBOOK_COUNT 0x01
|
||||
#define OBJ_DIVE 0x3000
|
||||
@ -94,6 +123,7 @@ typedef struct mares_iconhd_device_t {
|
||||
unsigned char version[140];
|
||||
unsigned int model;
|
||||
unsigned int packetsize;
|
||||
unsigned int ble;
|
||||
} mares_iconhd_device_t;
|
||||
|
||||
static dc_status_t mares_iconhd_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
|
||||
@ -161,6 +191,10 @@ mares_iconhd_get_model (mares_iconhd_device_t *device)
|
||||
{"Smart Air", SMARTAIR},
|
||||
{"Quad", QUAD},
|
||||
{"Horizon", HORIZON},
|
||||
{"Puck Air 2", PUCKAIR2},
|
||||
{"Sirius", SIRIUS},
|
||||
{"Quad Ci", QUADCI},
|
||||
{"Puck4", PUCK4},
|
||||
};
|
||||
|
||||
// Check the product name in the version packet against the list
|
||||
@ -177,44 +211,57 @@ mares_iconhd_get_model (mares_iconhd_device_t *device)
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_packet (mares_iconhd_device_t *device,
|
||||
const unsigned char command[], unsigned int csize,
|
||||
unsigned char answer[], unsigned int asize)
|
||||
mares_iconhd_packet_fixed (mares_iconhd_device_t *device,
|
||||
unsigned char cmd,
|
||||
const unsigned char data[], unsigned int size,
|
||||
unsigned char answer[], unsigned int asize,
|
||||
unsigned int *actual)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
assert (csize >= 2);
|
||||
dc_transport_t transport = dc_iostream_get_transport (device->iostream);
|
||||
|
||||
if (device_is_cancelled (abstract))
|
||||
return DC_STATUS_CANCELLED;
|
||||
|
||||
// Send the command header to the dive computer.
|
||||
status = dc_iostream_write (device->iostream, command, 2, NULL);
|
||||
const unsigned char command[2] = {
|
||||
cmd, cmd ^ XOR,
|
||||
};
|
||||
status = dc_iostream_write (device->iostream, command, sizeof(command), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
ERROR (abstract->context, "Failed to send the command header.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Send the command payload to the dive computer.
|
||||
if (size && transport == DC_TRANSPORT_BLE) {
|
||||
status = dc_iostream_write (device->iostream, data, size, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command data.");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// Receive the header byte.
|
||||
unsigned char header[1] = {0};
|
||||
status = dc_iostream_read (device->iostream, header, sizeof (header), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the answer.");
|
||||
ERROR (abstract->context, "Failed to receive the packet header.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Verify the header byte.
|
||||
if (header[0] != ACK) {
|
||||
ERROR (abstract->context, "Unexpected answer byte.");
|
||||
ERROR (abstract->context, "Unexpected packet header byte (%02x).", header[0]);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Send the command payload to the dive computer.
|
||||
if (csize > 2) {
|
||||
status = dc_iostream_write (device->iostream, command + 2, csize - 2, NULL);
|
||||
if (size && transport != DC_TRANSPORT_BLE) {
|
||||
status = dc_iostream_write (device->iostream, data, size, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
ERROR (abstract->context, "Failed to send the command data.");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
@ -222,7 +269,7 @@ mares_iconhd_packet (mares_iconhd_device_t *device,
|
||||
// Read the packet.
|
||||
status = dc_iostream_read (device->iostream, answer, asize, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the answer.");
|
||||
ERROR (abstract->context, "Failed to receive the packet data.");
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -230,25 +277,130 @@ mares_iconhd_packet (mares_iconhd_device_t *device,
|
||||
unsigned char trailer[1] = {0};
|
||||
status = dc_iostream_read (device->iostream, trailer, sizeof (trailer), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the answer.");
|
||||
ERROR (abstract->context, "Failed to receive the packet trailer.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Verify the trailer byte.
|
||||
if (trailer[0] != EOF) {
|
||||
ERROR (abstract->context, "Unexpected answer byte.");
|
||||
if (trailer[0] != END) {
|
||||
ERROR (abstract->context, "Unexpected packet trailer byte (%02x).", trailer[0]);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (actual) {
|
||||
*actual = asize;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_transfer (mares_iconhd_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize)
|
||||
mares_iconhd_packet_variable (mares_iconhd_device_t *device,
|
||||
unsigned char cmd,
|
||||
const unsigned char data[], unsigned int size,
|
||||
unsigned char answer[], unsigned int asize,
|
||||
unsigned int *actual)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
unsigned char packet[MAXPACKET] = {0};
|
||||
size_t length = 0;
|
||||
|
||||
if (device_is_cancelled (abstract))
|
||||
return DC_STATUS_CANCELLED;
|
||||
|
||||
// Send the command header to the dive computer.
|
||||
const unsigned char command[2] = {
|
||||
cmd, cmd ^ XOR,
|
||||
};
|
||||
status = dc_iostream_write (device->iostream, command, sizeof(command), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command header.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Read either the entire data packet (if there is no command data to send),
|
||||
// or only the header byte (if there is also command data to send).
|
||||
status = dc_iostream_read (device->iostream, packet, sizeof (packet), &length);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the packet header.");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
// Send the command payload to the dive computer.
|
||||
status = dc_iostream_write (device->iostream, data, size, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command data.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Read the data packet.
|
||||
size_t len = 0;
|
||||
status = dc_iostream_read (device->iostream, packet + length, sizeof (packet) - length, &len);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the packet data.");
|
||||
return status;
|
||||
}
|
||||
|
||||
length += len;
|
||||
}
|
||||
|
||||
if (length < 2 || length - 2 > asize) {
|
||||
ERROR (abstract->context, "Unexpected packet length (" DC_PRINTF_SIZE ").", length);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Verify the header byte.
|
||||
if (packet[0] != ACK) {
|
||||
ERROR (abstract->context, "Unexpected packet header byte (%02x).", packet[0]);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Verify the trailer byte.
|
||||
if (packet[length - 1] != END) {
|
||||
ERROR (abstract->context, "Unexpected packet trailer byte (%02x).", packet[length - 1]);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (actual == NULL) {
|
||||
// Verify the actual length.
|
||||
if (length - 2 != asize) {
|
||||
ERROR (abstract->context, "Unexpected packet length (" DC_PRINTF_SIZE ").", length - 2);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
} else {
|
||||
// Return the actual length.
|
||||
*actual = length - 2;
|
||||
}
|
||||
|
||||
memcpy (answer, packet + 1, length - 2);
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_packet (mares_iconhd_device_t *device,
|
||||
unsigned char cmd,
|
||||
const unsigned char data[], unsigned int size,
|
||||
unsigned char answer[], unsigned int asize,
|
||||
unsigned int *actual)
|
||||
{
|
||||
dc_transport_t transport = dc_iostream_get_transport (device->iostream);
|
||||
|
||||
if (transport == DC_TRANSPORT_BLE && device->ble == VARIABLE) {
|
||||
return mares_iconhd_packet_variable (device, cmd, data, size, answer, asize, actual);
|
||||
} else {
|
||||
return mares_iconhd_packet_fixed (device, cmd, data, size, answer, asize, actual);
|
||||
}
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_transfer (mares_iconhd_device_t *device, unsigned char cmd, const unsigned char data[], unsigned int size, unsigned char answer[], unsigned int asize, unsigned int *actual)
|
||||
{
|
||||
unsigned int nretries = 0;
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
while ((rc = mares_iconhd_packet (device, command, csize, answer, asize)) != DC_STATUS_SUCCESS) {
|
||||
while ((rc = mares_iconhd_packet (device, cmd, data, size, answer, asize, actual)) != DC_STATUS_SUCCESS) {
|
||||
// Automatically discard a corrupted packet,
|
||||
// and request a new one.
|
||||
if (rc != DC_STATUS_PROTOCOL && rc != DC_STATUS_TIMEOUT)
|
||||
@ -272,7 +424,9 @@ mares_iconhd_read_object(mares_iconhd_device_t *device, dc_event_progress_t *pro
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
dc_transport_t transport = dc_iostream_get_transport (device->iostream);
|
||||
const unsigned int maxpacket = (transport == DC_TRANSPORT_BLE) ? 124 : 504;
|
||||
const unsigned int maxpacket = (transport == DC_TRANSPORT_BLE) ?
|
||||
(device->ble == VARIABLE ? MAXPACKET - 3 : 124) :
|
||||
504;
|
||||
|
||||
// Update and emit a progress event.
|
||||
unsigned int initial = 0;
|
||||
@ -283,23 +437,21 @@ mares_iconhd_read_object(mares_iconhd_device_t *device, dc_event_progress_t *pro
|
||||
|
||||
// Transfer the init packet.
|
||||
unsigned char rsp_init[16];
|
||||
unsigned char cmd_init[18] = {
|
||||
CMD_OBJ_INIT,
|
||||
CMD_OBJ_INIT ^ XOR,
|
||||
unsigned char cmd_init[16] = {
|
||||
0x40,
|
||||
(index >> 0) & 0xFF,
|
||||
(index >> 8) & 0xFF,
|
||||
subindex & 0xFF
|
||||
};
|
||||
memset (cmd_init + 6, 0x00, sizeof(cmd_init) - 6);
|
||||
status = mares_iconhd_transfer (device, cmd_init, sizeof (cmd_init), rsp_init, sizeof (rsp_init));
|
||||
status = mares_iconhd_transfer (device, CMD_OBJ_INIT, cmd_init, sizeof (cmd_init), rsp_init, sizeof (rsp_init), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to transfer the init packet.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Verify the packet header.
|
||||
if (memcmp (cmd_init + 3, rsp_init + 1, 3) != 0) {
|
||||
if (memcmp (cmd_init + 1, rsp_init + 1, 3) != 0) {
|
||||
ERROR (abstract->context, "Unexpected packet header.");
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
@ -346,14 +498,21 @@ mares_iconhd_read_object(mares_iconhd_device_t *device, dc_event_progress_t *pro
|
||||
}
|
||||
|
||||
// Transfer the segment packet.
|
||||
unsigned int length = 0;
|
||||
unsigned char rsp_segment[1 + 504];
|
||||
unsigned char cmd_segment[] = {cmd, cmd ^ XOR};
|
||||
status = mares_iconhd_transfer (device, cmd_segment, sizeof (cmd_segment), rsp_segment, len + 1);
|
||||
status = mares_iconhd_transfer (device, cmd, NULL, 0, rsp_segment, len + 1, &length);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to transfer the segment packet.");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (length < 1) {
|
||||
ERROR (abstract->context, "Unexpected packet length (%u).", length);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
length--;
|
||||
|
||||
// Verify the packet header.
|
||||
if ((rsp_segment[0] & 0xF0) >> 4 != toggle) {
|
||||
ERROR (abstract->context, "Unexpected packet header (%02x).", rsp_segment[0]);
|
||||
@ -361,12 +520,12 @@ mares_iconhd_read_object(mares_iconhd_device_t *device, dc_event_progress_t *pro
|
||||
}
|
||||
|
||||
// Append the payload to the output buffer.
|
||||
if (!dc_buffer_append (buffer, rsp_segment + 1, len)) {
|
||||
if (!dc_buffer_append (buffer, rsp_segment + 1, length)) {
|
||||
ERROR (abstract->context, "Insufficient buffer space available.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
nbytes += len;
|
||||
nbytes += length;
|
||||
npackets++;
|
||||
|
||||
// Update and emit the progress events.
|
||||
@ -380,7 +539,7 @@ mares_iconhd_read_object(mares_iconhd_device_t *device, dc_event_progress_t *pro
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream)
|
||||
mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream, unsigned int model)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
mares_iconhd_device_t *device = NULL;
|
||||
@ -403,10 +562,11 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_
|
||||
memset (device->version, 0, sizeof (device->version));
|
||||
device->model = 0;
|
||||
device->packetsize = 0;
|
||||
device->ble = ISSIRIUS(model) ? VARIABLE : FIXED;
|
||||
|
||||
// Create the packet stream.
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
status = dc_packet_open (&device->iostream, context, iostream, 20, 20);
|
||||
if (transport == DC_TRANSPORT_BLE && device->ble == FIXED) {
|
||||
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;
|
||||
@ -447,9 +607,8 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_
|
||||
dc_iostream_purge (device->iostream, DC_DIRECTION_ALL);
|
||||
|
||||
// Send the version command.
|
||||
unsigned char command[] = {CMD_VERSION, CMD_VERSION ^ XOR};
|
||||
status = mares_iconhd_transfer (device, command, sizeof (command),
|
||||
device->version, sizeof (device->version));
|
||||
status = mares_iconhd_transfer (device, CMD_VERSION, NULL, 0,
|
||||
device->version, sizeof (device->version), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
goto error_free_iostream;
|
||||
}
|
||||
@ -460,9 +619,8 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_
|
||||
// Read the size of the flash memory.
|
||||
unsigned int memsize = 0;
|
||||
if (device->model == QUAD) {
|
||||
unsigned char cmd_flash[] = {CMD_FLASHSIZE, CMD_FLASHSIZE ^ XOR};
|
||||
unsigned char rsp_flash[4] = {0};
|
||||
status = mares_iconhd_transfer (device, cmd_flash, sizeof (cmd_flash), rsp_flash, sizeof (rsp_flash));
|
||||
status = mares_iconhd_transfer (device, CMD_FLASHSIZE, NULL, 0, rsp_flash, sizeof (rsp_flash), NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
WARNING (context, "Failed to read the flash memory size.");
|
||||
} else {
|
||||
@ -521,7 +679,7 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_
|
||||
|
||||
|
||||
error_free_iostream:
|
||||
if (transport == DC_TRANSPORT_BLE) {
|
||||
if (transport == DC_TRANSPORT_BLE && device->ble == FIXED) {
|
||||
dc_iostream_close (device->iostream);
|
||||
}
|
||||
error_free:
|
||||
@ -534,9 +692,10 @@ static dc_status_t
|
||||
mares_iconhd_device_close (dc_device_t *abstract)
|
||||
{
|
||||
mares_iconhd_device_t *device = (mares_iconhd_device_t *) abstract;
|
||||
dc_transport_t transport = dc_iostream_get_transport (device->iostream);
|
||||
|
||||
// Close the packet stream.
|
||||
if (dc_iostream_get_transport (device->iostream) == DC_TRANSPORT_BLE) {
|
||||
if (transport == DC_TRANSPORT_BLE && device->ble == FIXED) {
|
||||
return dc_iostream_close (device->iostream);
|
||||
}
|
||||
|
||||
@ -575,7 +734,7 @@ mares_iconhd_device_read (dc_device_t *abstract, unsigned int address, unsigned
|
||||
len = device->packetsize;
|
||||
|
||||
// Read the packet.
|
||||
unsigned char command[] = {CMD_READ, CMD_READ ^ XOR,
|
||||
unsigned char command[] = {
|
||||
(address ) & 0xFF,
|
||||
(address >> 8) & 0xFF,
|
||||
(address >> 16) & 0xFF,
|
||||
@ -584,7 +743,7 @@ mares_iconhd_device_read (dc_device_t *abstract, unsigned int address, unsigned
|
||||
(len >> 8) & 0xFF,
|
||||
(len >> 16) & 0xFF,
|
||||
(len >> 24) & 0xFF};
|
||||
rc = mares_iconhd_transfer (device, command, sizeof (command), data, len);
|
||||
rc = mares_iconhd_transfer (device, CMD_READ, command, sizeof (command), data, len, NULL);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
@ -641,6 +800,21 @@ mares_iconhd_device_foreach_raw (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
|
||||
const mares_iconhd_layout_t *layout = device->layout;
|
||||
|
||||
// Read the serial number.
|
||||
unsigned char serial[4] = {0};
|
||||
rc = mares_iconhd_device_read (abstract, 0x0C, serial, sizeof (serial));
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the memory.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = device->model;
|
||||
devinfo.firmware = 0;
|
||||
devinfo.serial = array_uint32_le (serial);
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
// Enable progress notifications.
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
progress.maximum = layout->rb_profile_end - layout->rb_profile_begin;
|
||||
@ -690,7 +864,7 @@ mares_iconhd_device_foreach_raw (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
dc_rbstream_t *rbstream = NULL;
|
||||
rc = dc_rbstream_new (&rbstream, abstract, 1, device->packetsize, layout->rb_profile_begin, layout->rb_profile_end, eop);
|
||||
rc = dc_rbstream_new (&rbstream, abstract, 1, device->packetsize, layout->rb_profile_begin, layout->rb_profile_end, eop, DC_RBSTREAM_BACKWARD);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
return rc;
|
||||
@ -717,7 +891,7 @@ mares_iconhd_device_foreach_raw (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
|
||||
// Get the number of samples in the profile data.
|
||||
unsigned int type = 0, nsamples = 0;
|
||||
if (model == SMART || model == SMARTAPNEA || model == SMARTAIR) {
|
||||
if (ISSMART(model)) {
|
||||
type = array_uint16_le (buffer + offset - header + 2);
|
||||
nsamples = array_uint16_le (buffer + offset - header + 0);
|
||||
} else {
|
||||
@ -846,6 +1020,33 @@ mares_iconhd_device_foreach_object (dc_device_t *abstract, dc_dive_callback_t ca
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Read the serial number.
|
||||
rc = mares_iconhd_read_object (device, NULL, buffer, OBJ_DEVICE, OBJ_DEVICE_SERIAL);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the serial number.");
|
||||
dc_buffer_free (buffer);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (dc_buffer_get_size (buffer) < 16) {
|
||||
ERROR (abstract->context, "Unexpected number of bytes received (" DC_PRINTF_SIZE ").",
|
||||
dc_buffer_get_size (buffer));
|
||||
dc_buffer_free (buffer);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
unsigned int serial = array_convert_str2num (dc_buffer_get_data (buffer) + 10, 6);
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = device->model;
|
||||
devinfo.firmware = 0;
|
||||
devinfo.serial = serial;
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
// Erase the buffer.
|
||||
dc_buffer_clear (buffer);
|
||||
|
||||
// Read the number of dives.
|
||||
rc = mares_iconhd_read_object (device, NULL, buffer, OBJ_LOGBOOK, OBJ_LOGBOOK_COUNT);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
@ -908,7 +1109,6 @@ mares_iconhd_device_foreach_object (dc_device_t *abstract, dc_dive_callback_t ca
|
||||
static dc_status_t
|
||||
mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
mares_iconhd_device_t *device = (mares_iconhd_device_t *) abstract;
|
||||
|
||||
// Emit a vendor event.
|
||||
@ -917,22 +1117,7 @@ mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback,
|
||||
vendor.size = sizeof (device->version);
|
||||
device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
|
||||
|
||||
// Read the serial number.
|
||||
unsigned char serial[4] = {0};
|
||||
rc = mares_iconhd_device_read (abstract, 0x0C, serial, sizeof (serial));
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the memory.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = device->model;
|
||||
devinfo.firmware = 0;
|
||||
devinfo.serial = array_uint32_le (serial);
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
if (device->model == GENIUS || device->model == HORIZON) {
|
||||
if (ISGENIUS(device->model)) {
|
||||
return mares_iconhd_device_foreach_object (abstract, callback, userdata);
|
||||
} else {
|
||||
return mares_iconhd_device_foreach_raw (abstract, callback, userdata);
|
||||
|
||||
@ -32,10 +32,10 @@ extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
dc_status_t
|
||||
mares_iconhd_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
mares_iconhd_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
|
||||
|
||||
dc_status_t
|
||||
mares_iconhd_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
mares_iconhd_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -45,6 +45,23 @@
|
||||
#define QUADAIR 0x23
|
||||
#define SMARTAIR 0x24
|
||||
#define HORIZON 0x2C
|
||||
#define PUCKAIR2 0x2D
|
||||
#define SIRIUS 0x2F
|
||||
#define QUADCI 0x31
|
||||
#define PUCK4 0x35
|
||||
|
||||
#define ISSMART(model) ( \
|
||||
(model) == SMART || \
|
||||
(model) == SMARTAPNEA || \
|
||||
(model) == SMARTAIR)
|
||||
|
||||
#define ISGENIUS(model) ( \
|
||||
(model) == GENIUS || \
|
||||
(model) == HORIZON || \
|
||||
(model) == PUCKAIR2 || \
|
||||
(model) == SIRIUS || \
|
||||
(model) == QUADCI || \
|
||||
(model) == PUCK4)
|
||||
|
||||
#define NGASMIXES_ICONHD 3
|
||||
#define NGASMIXES_GENIUS 5
|
||||
@ -264,7 +281,6 @@ static const mares_iconhd_layout_t horizon = {
|
||||
0x54 + 8, /* tanks */
|
||||
};
|
||||
|
||||
static dc_status_t mares_iconhd_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -272,7 +288,6 @@ static dc_status_t mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, d
|
||||
static const dc_parser_vtable_t mares_iconhd_parser_vtable = {
|
||||
sizeof(mares_iconhd_parser_t),
|
||||
DC_FAMILY_MARES_ICONHD,
|
||||
mares_iconhd_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -282,28 +297,6 @@ static const dc_parser_vtable_t mares_iconhd_parser_vtable = {
|
||||
NULL /* destroy */
|
||||
};
|
||||
|
||||
static unsigned int
|
||||
mares_genius_isvalid (const unsigned char data[], size_t size, unsigned int type)
|
||||
{
|
||||
if (size < 10) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int head = array_uint32_be(data);
|
||||
unsigned int tail = array_uint32_be(data + size - 4);
|
||||
if (head != type || tail != type) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned short crc = array_uint16_le(data + size - 6);
|
||||
unsigned short ccrc = checksum_crc16_ccitt(data + 4, size - 10, 0x0000, 0x0000);
|
||||
if (crc != ccrc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_cache (mares_iconhd_parser_t *parser)
|
||||
{
|
||||
@ -334,7 +327,7 @@ mares_iconhd_cache (mares_iconhd_parser_t *parser)
|
||||
|
||||
// Get the number of samples in the profile data.
|
||||
unsigned int type = 0, nsamples = 0;
|
||||
if (parser->model == SMART || parser->model == SMARTAPNEA || parser->model == SMARTAIR) {
|
||||
if (ISSMART (parser->model)) {
|
||||
type = array_uint16_le (data + length - header + 2);
|
||||
nsamples = array_uint16_le (data + length - header + 0);
|
||||
} else {
|
||||
@ -389,7 +382,7 @@ mares_iconhd_cache (mares_iconhd_parser_t *parser)
|
||||
}
|
||||
|
||||
const unsigned char *p = data + length - headersize;
|
||||
if (parser->model != SMART && parser->model != SMARTAPNEA && parser->model != SMARTAIR) {
|
||||
if (!ISSMART(parser->model)) {
|
||||
p += 4;
|
||||
}
|
||||
|
||||
@ -401,12 +394,12 @@ mares_iconhd_cache (mares_iconhd_parser_t *parser)
|
||||
unsigned int samplerate = 0;
|
||||
if (parser->model == SMARTAPNEA) {
|
||||
unsigned int idx = (settings & 0x0600) >> 9;
|
||||
interval = 1;
|
||||
samplerate = 1 << idx;
|
||||
interval = 1000 / samplerate;
|
||||
} else {
|
||||
const unsigned int intervals[] = {1, 5, 10, 20};
|
||||
unsigned int idx = (settings & 0x0C00) >> 10;
|
||||
interval = intervals[idx];
|
||||
interval = intervals[idx] * 1000;
|
||||
samplerate = 1;
|
||||
}
|
||||
|
||||
@ -547,30 +540,22 @@ mares_genius_cache (mares_iconhd_parser_t *parser)
|
||||
// Get the dive mode.
|
||||
unsigned int mode = settings & 0xF;
|
||||
|
||||
// Get the sample size.
|
||||
unsigned int samplesize = logformat == 1 ? SDPT_SIZE: DPRS_SIZE;
|
||||
|
||||
// Calculate the total number of bytes for this dive.
|
||||
unsigned int nbytes = headersize + 4 + DSTR_SIZE + TISS_SIZE + nsamples * samplesize + (nsamples / 4) * AIRS_SIZE + DEND_SIZE;
|
||||
if (nbytes > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Get the profile type and version.
|
||||
unsigned int profile_type = array_uint16_le (data + headersize);
|
||||
unsigned int profile_minor = data[headersize + 2];
|
||||
unsigned int profile_major = data[headersize + 3];
|
||||
|
||||
// Get the surface timeout setting (in minutes).
|
||||
// For older firmware versions the value is hardcoded to 3 minutes, but
|
||||
// starting with the newer v01.02.00 firmware the value is configurable and
|
||||
// stored in the settings. To detect whether the setting is available, we
|
||||
// need to check the profile version instead of the header version.
|
||||
unsigned int surftime = 3;
|
||||
if (profile_type == 0 &&
|
||||
OBJVERSION(profile_major,profile_minor) >= OBJVERSION(1,0)) {
|
||||
surftime = (settings >> 13) & 0x3F;
|
||||
if (headersize + 4 <= size) {
|
||||
// Get the profile type and version.
|
||||
unsigned int profile_type = array_uint16_le (data + headersize);
|
||||
unsigned int profile_minor = data[headersize + 2];
|
||||
unsigned int profile_major = data[headersize + 3];
|
||||
|
||||
if (profile_type == 0 &&
|
||||
OBJVERSION(profile_major,profile_minor) >= OBJVERSION(1,0)) {
|
||||
surftime = (settings >> 13) & 0x3F;
|
||||
}
|
||||
}
|
||||
|
||||
// Gas mixes and tanks.
|
||||
@ -621,11 +606,11 @@ mares_genius_cache (mares_iconhd_parser_t *parser)
|
||||
parser->logformat = logformat;
|
||||
parser->mode = mode;
|
||||
parser->nsamples = nsamples;
|
||||
parser->samplesize = samplesize;
|
||||
parser->samplesize = 0;
|
||||
parser->headersize = headersize;
|
||||
parser->settings = settings;
|
||||
parser->surftime = surftime * 60;
|
||||
parser->interval = 5;
|
||||
parser->interval = 5000;
|
||||
parser->samplerate = 1;
|
||||
parser->ntanks = ntanks;
|
||||
parser->ngasmixes = ngasmixes;
|
||||
@ -648,7 +633,7 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser)
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (parser->model == GENIUS || parser->model == HORIZON) {
|
||||
if (ISGENIUS(parser->model)) {
|
||||
return mares_genius_cache (parser);
|
||||
} else {
|
||||
return mares_iconhd_cache (parser);
|
||||
@ -656,7 +641,7 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser)
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
{
|
||||
mares_iconhd_parser_t *parser = NULL;
|
||||
|
||||
@ -664,7 +649,7 @@ mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (mares_iconhd_parser_t *) dc_parser_allocate (context, &mares_iconhd_parser_vtable);
|
||||
parser = (mares_iconhd_parser_t *) dc_parser_allocate (context, &mares_iconhd_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -674,7 +659,7 @@ mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i
|
||||
parser->model = model;
|
||||
parser->cached = 0;
|
||||
parser->logformat = 0;
|
||||
parser->mode = (model == GENIUS || model == HORIZON) ? GENIUS_AIR : ICONHD_AIR;
|
||||
parser->mode = ISGENIUS(model) ? GENIUS_AIR : ICONHD_AIR;
|
||||
parser->nsamples = 0;
|
||||
parser->samplesize = 0;
|
||||
parser->headersize = 0;
|
||||
@ -701,41 +686,6 @@ mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
mares_iconhd_parser_t *parser = (mares_iconhd_parser_t *) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 0;
|
||||
parser->logformat = 0;
|
||||
parser->mode = (parser->model == GENIUS || parser->model == HORIZON) ? GENIUS_AIR : ICONHD_AIR;
|
||||
parser->nsamples = 0;
|
||||
parser->samplesize = 0;
|
||||
parser->headersize = 0;
|
||||
parser->settings = 0;
|
||||
parser->surftime = 0;
|
||||
parser->interval = 0;
|
||||
parser->samplerate = 0;
|
||||
parser->ntanks = 0;
|
||||
parser->ngasmixes = 0;
|
||||
for (unsigned int i = 0; i < NGASMIXES; ++i) {
|
||||
parser->gasmix[i].oxygen = 0;
|
||||
parser->gasmix[i].helium = 0;
|
||||
}
|
||||
for (unsigned int i = 0; i < NTANKS; ++i) {
|
||||
parser->tank[i].volume = 0;
|
||||
parser->tank[i].workpressure = 0;
|
||||
parser->tank[i].beginpressure = 0;
|
||||
parser->tank[i].endpressure = 0;
|
||||
}
|
||||
parser->layout = NULL;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -748,9 +698,9 @@ mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime
|
||||
|
||||
// Pointer to the header data.
|
||||
const unsigned char *p = abstract->data;
|
||||
if (parser->model != GENIUS && parser->model != HORIZON) {
|
||||
if (!ISGENIUS(parser->model)) {
|
||||
p += abstract->size - parser->headersize;
|
||||
if (parser->model != SMART && parser->model != SMARTAPNEA && parser->model != SMARTAIR) {
|
||||
if (!ISSMART(parser->model)) {
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
@ -759,7 +709,7 @@ mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime
|
||||
p += parser->layout->datetime;
|
||||
|
||||
if (datetime) {
|
||||
if (parser->model == GENIUS || parser->model == HORIZON) {
|
||||
if (ISGENIUS(parser->model)) {
|
||||
unsigned int timestamp = array_uint32_le (p);
|
||||
datetime->hour = (timestamp ) & 0x1F;
|
||||
datetime->minute = (timestamp >> 5) & 0x3F;
|
||||
@ -794,9 +744,9 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
|
||||
|
||||
// Pointer to the header data.
|
||||
const unsigned char *p = abstract->data;
|
||||
if (parser->model != GENIUS && parser->model != HORIZON) {
|
||||
if (!ISGENIUS(parser->model)) {
|
||||
p += abstract->size - parser->headersize;
|
||||
if (parser->model != SMART && parser->model != SMARTAPNEA && parser->model != SMARTAIR) {
|
||||
if (!ISSMART(parser->model)) {
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
@ -807,7 +757,7 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
|
||||
extra = 8;
|
||||
}
|
||||
|
||||
unsigned int metric = (parser->model == GENIUS || parser->model == HORIZON) ?
|
||||
unsigned int metric = ISGENIUS(parser->model) ?
|
||||
p[0x34 + extra] : parser->settings & 0x0100;
|
||||
|
||||
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
|
||||
@ -820,7 +770,7 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
|
||||
if (parser->layout->divetime != UNSUPPORTED) {
|
||||
*((unsigned int *) value) = array_uint16_le (p + parser->layout->divetime);
|
||||
} else {
|
||||
*((unsigned int *) value) = parser->nsamples * parser->interval - parser->surftime;
|
||||
*((unsigned int *) value) = parser->nsamples * parser->interval / 1000 - parser->surftime;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_MAXDEPTH:
|
||||
@ -830,6 +780,7 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
|
||||
gasmix->helium = parser->gasmix[flags].helium / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -857,12 +808,13 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
|
||||
} else {
|
||||
tank->gasmix = DC_GASMIX_UNKNOWN;
|
||||
}
|
||||
tank->usage = DC_USAGE_NONE;
|
||||
break;
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
*((double *) value) = array_uint16_le (p + parser->layout->atmospheric) / (1000.0 * parser->layout->atmospheric_divisor);
|
||||
break;
|
||||
case DC_FIELD_SALINITY:
|
||||
if (parser->model == GENIUS || parser->model == HORIZON) {
|
||||
if (ISGENIUS(parser->model)) {
|
||||
unsigned int salinity = (parser->settings >> 5) & 0x03;
|
||||
switch (salinity) {
|
||||
case WATER_FRESH:
|
||||
@ -904,7 +856,7 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
|
||||
*((double *) value) = (signed short) array_uint16_le (p + parser->layout->temperature_max) / 10.0;
|
||||
break;
|
||||
case DC_FIELD_DIVEMODE:
|
||||
if (parser->model == GENIUS || parser->model == HORIZON) {
|
||||
if (ISGENIUS(parser->model)) {
|
||||
switch (parser->mode) {
|
||||
case GENIUS_AIR:
|
||||
case GENIUS_NITROX_SINGLE:
|
||||
@ -952,64 +904,16 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
|
||||
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
mares_iconhd_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
mares_iconhd_parser_t *parser = (mares_iconhd_parser_t *) abstract;
|
||||
|
||||
// Cache the parser data.
|
||||
dc_status_t rc = mares_iconhd_parser_cache (parser);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
const unsigned char *data = abstract->data;
|
||||
|
||||
if (parser->samplerate > 1) {
|
||||
// The Smart Apnea supports multiple samples per second
|
||||
// (e.g. 2, 4 or 8). Since our smallest unit of time is one
|
||||
// second, we can't represent this, and the extra samples
|
||||
// will get dropped.
|
||||
WARNING(abstract->context, "Multiple samples per second are not supported!");
|
||||
}
|
||||
|
||||
// Previous gas mix - initialize with impossible value
|
||||
unsigned int gasmix_previous = 0xFFFFFFFF;
|
||||
|
||||
unsigned int offset = 4;
|
||||
unsigned int marker = 0;
|
||||
if (parser->model == GENIUS || parser->model == HORIZON) {
|
||||
// Skip the dive header.
|
||||
data += parser->headersize;
|
||||
|
||||
// Check the profile type and version.
|
||||
unsigned int type = array_uint16_le (data);
|
||||
unsigned int minor = data[2];
|
||||
unsigned int major = data[3];
|
||||
if (type > 1 ||
|
||||
(type == 0 && OBJVERSION(major,minor) > OBJVERSION(1,0)) ||
|
||||
(type == 1 && OBJVERSION(major,minor) > OBJVERSION(0,2))) {
|
||||
ERROR (abstract->context, "Unsupported object type (%u) or version (%u.%u).",
|
||||
type, major, minor);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Skip the DSTR record.
|
||||
if (!mares_genius_isvalid (data + offset, DSTR_SIZE, DSTR_TYPE)) {
|
||||
ERROR (abstract->context, "Invalid DSTR record.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
offset += DSTR_SIZE;
|
||||
|
||||
// Skip the TISS record.
|
||||
if (!mares_genius_isvalid (data + offset, TISS_SIZE, TISS_TYPE)) {
|
||||
ERROR (abstract->context, "Invalid TISS record.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
offset += TISS_SIZE;
|
||||
|
||||
// Size of the record type marker.
|
||||
marker = 4;
|
||||
}
|
||||
|
||||
unsigned int time = 0;
|
||||
unsigned int nsamples = 0;
|
||||
while (nsamples < parser->nsamples) {
|
||||
@ -1021,118 +925,73 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
unsigned int surftime = array_uint16_le (data + offset + 4);
|
||||
|
||||
// Surface Time (seconds).
|
||||
time += surftime;
|
||||
time += surftime * 1000;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Surface Depth (0 m).
|
||||
sample.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
offset += parser->samplesize;
|
||||
nsamples++;
|
||||
|
||||
for (unsigned int i = 0; i < divetime; ++i) {
|
||||
unsigned int count = divetime * parser->samplerate;
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
// Time (seconds).
|
||||
time += parser->interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
unsigned int depth = array_uint16_le (data + offset);
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
offset += 2 * parser->samplerate;
|
||||
offset += 2;
|
||||
}
|
||||
} else if (parser->model != GENIUS && parser->model != HORIZON && parser->mode == ICONHD_FREEDIVE) {
|
||||
} else if (parser->mode == ICONHD_FREEDIVE) {
|
||||
unsigned int maxdepth = array_uint16_le (data + offset + 0);
|
||||
unsigned int divetime = array_uint16_le (data + offset + 2);
|
||||
unsigned int surftime = array_uint16_le (data + offset + 4);
|
||||
|
||||
// Surface Time (seconds).
|
||||
time += surftime;
|
||||
time += surftime * 1000;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Surface Depth (0 m).
|
||||
sample.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Dive Time (seconds).
|
||||
time += divetime;
|
||||
time += divetime * 1000;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Maximum Depth (1/10 m).
|
||||
sample.depth = maxdepth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
offset += parser->samplesize;
|
||||
nsamples++;
|
||||
} else {
|
||||
unsigned int depth = 0, temperature = 0;
|
||||
unsigned int gasmix = 0, alarms = 0;
|
||||
unsigned int decostop = 0, decodepth = 0, decotime = 0, tts = 0;
|
||||
unsigned int bookmark = 0;
|
||||
if (parser->model == GENIUS || parser->model == HORIZON) {
|
||||
if (parser->logformat == 1) {
|
||||
if (!mares_genius_isvalid (data + offset, SDPT_SIZE, SDPT_TYPE)) {
|
||||
ERROR (abstract->context, "Invalid SDPT record.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned int misc = 0, deco = 0;
|
||||
depth = array_uint16_le (data + offset + marker + 2);
|
||||
temperature = array_uint16_le (data + offset + marker + 6);
|
||||
alarms = array_uint32_le (data + offset + marker + 0x14);
|
||||
misc = array_uint32_le (data + offset + marker + 0x18);
|
||||
deco = array_uint32_le (data + offset + marker + 0x1C);
|
||||
bookmark = (misc >> 2) & 0x0F;
|
||||
gasmix = (misc >> 6) & 0x0F;
|
||||
decostop = (misc >> 10) & 0x01;
|
||||
if (decostop) {
|
||||
decodepth = (deco >> 3) & 0x7F;
|
||||
decotime = (deco >> 10) & 0xFF;
|
||||
tts = (deco >> 18) & 0x3FFF;
|
||||
} else {
|
||||
decotime = deco & 0xFF;
|
||||
}
|
||||
} else {
|
||||
if (!mares_genius_isvalid (data + offset, DPRS_SIZE, DPRS_TYPE)) {
|
||||
ERROR (abstract->context, "Invalid DPRS record.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned int misc = 0;
|
||||
depth = array_uint16_le (data + offset + marker + 0);
|
||||
temperature = array_uint16_le (data + offset + marker + 4);
|
||||
decotime = array_uint16_le (data + offset + marker + 0x0A);
|
||||
alarms = array_uint32_le (data + offset + marker + 0x0C);
|
||||
misc = array_uint32_le (data + offset + marker + 0x14);
|
||||
bookmark = (misc >> 2) & 0x0F;
|
||||
gasmix = (misc >> 6) & 0x0F;
|
||||
decostop = (misc >> 18) & 0x01;
|
||||
decodepth = (misc >> 19) & 0x7F;
|
||||
}
|
||||
} else {
|
||||
depth = array_uint16_le (data + offset + 0);
|
||||
temperature = array_uint16_le (data + offset + 2) & 0x0FFF;
|
||||
gasmix = (data[offset + 3] & 0xF0) >> 4;
|
||||
}
|
||||
unsigned int depth = array_uint16_le (data + offset + 0);
|
||||
unsigned int temperature = array_uint16_le (data + offset + 2) & 0x0FFF;
|
||||
unsigned int gasmix = (data[offset + 3] & 0xF0) >> 4;
|
||||
|
||||
// Time (seconds).
|
||||
time += parser->interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Temperature (1/10 °C).
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
// Current gas mix
|
||||
if (parser->ngasmixes > 0) {
|
||||
@ -1142,95 +1001,264 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
|
||||
}
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
}
|
||||
|
||||
// Bookmark
|
||||
if (bookmark) {
|
||||
sample.event.type = SAMPLE_EVENT_BOOKMARK;
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = bookmark;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
}
|
||||
|
||||
if (parser->model == GENIUS || parser->model == HORIZON) {
|
||||
// Deco stop / NDL.
|
||||
if (decostop) {
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = decodepth;
|
||||
} else {
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.depth = 0.0;
|
||||
}
|
||||
sample.deco.time = decotime * 60;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
|
||||
// Alarms
|
||||
for (unsigned int v = alarms, i = 0; v; v >>= 1, ++i) {
|
||||
if ((v & 1) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (i) {
|
||||
case ALARM_FAST_ASCENT:
|
||||
case ALARM_UNCONTROLLED_ASCENT:
|
||||
sample.event.type = SAMPLE_EVENT_ASCENT;
|
||||
break;
|
||||
case ALARM_MISSED_DECO:
|
||||
case ALARM_DIVE_VIOLATION_DECO:
|
||||
sample.event.type = SAMPLE_EVENT_CEILING;
|
||||
break;
|
||||
default:
|
||||
sample.event.type = SAMPLE_EVENT_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sample.event.type != SAMPLE_EVENT_NONE) {
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = 0;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
offset += parser->samplesize;
|
||||
nsamples++;
|
||||
|
||||
// Some extra data.
|
||||
if (parser->layout->tanks != UNSUPPORTED && (nsamples % 4) == 0) {
|
||||
if ((parser->model == GENIUS || parser->model == HORIZON) &&
|
||||
!mares_genius_isvalid (data + offset, AIRS_SIZE, AIRS_TYPE)) {
|
||||
ERROR (abstract->context, "Invalid AIRS record.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Pressure (1/100 bar).
|
||||
unsigned int pressure = array_uint16_le(data + offset + marker + 0);
|
||||
if (gasmix < parser->ntanks) {
|
||||
sample.pressure.tank = gasmix;
|
||||
sample.pressure.value = pressure / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
} else if (pressure != 0) {
|
||||
WARNING (abstract->context, "Invalid tank with non-zero pressure.");
|
||||
}
|
||||
|
||||
offset += (parser->model == GENIUS || parser->model == HORIZON) ? AIRS_SIZE : 8;
|
||||
offset += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parser->model == GENIUS || parser->model == HORIZON) {
|
||||
// Skip the DEND record.
|
||||
if (!mares_genius_isvalid (data + offset, DEND_SIZE, DEND_TYPE)) {
|
||||
ERROR (abstract->context, "Invalid DEND record.");
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
mares_genius_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
mares_iconhd_parser_t *parser = (mares_iconhd_parser_t *) abstract;
|
||||
const unsigned char *data = abstract->data;
|
||||
const unsigned int size = abstract->size;
|
||||
|
||||
// Previous gas mix - initialize with impossible value
|
||||
unsigned int gasmix_previous = 0xFFFFFFFF;
|
||||
unsigned int tank = 0xFFFFFFFF;
|
||||
|
||||
// Skip the dive header.
|
||||
unsigned int offset = parser->headersize;
|
||||
|
||||
if (offset + 4 > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Check the profile type and version.
|
||||
unsigned int profile_type = array_uint16_le (data + offset);
|
||||
unsigned int profile_minor = data[offset + 2];
|
||||
unsigned int profile_major = data[offset + 3];
|
||||
if (profile_type > 1 ||
|
||||
(profile_type == 0 && OBJVERSION(profile_major,profile_minor) > OBJVERSION(1,0)) ||
|
||||
(profile_type == 1 && OBJVERSION(profile_major,profile_minor) > OBJVERSION(0,2))) {
|
||||
ERROR (abstract->context, "Unsupported object type (%u) or version (%u.%u).",
|
||||
profile_type, profile_major, profile_minor);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
offset += 4;
|
||||
|
||||
unsigned int time = 0;
|
||||
unsigned int marker = 4;
|
||||
while (offset < size) {
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
if (offset + 10 > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
offset += DEND_SIZE;
|
||||
|
||||
// Get the record type and length.
|
||||
unsigned int type = array_uint32_be(data + offset);
|
||||
unsigned int length = 0;
|
||||
switch (type) {
|
||||
case DSTR_TYPE:
|
||||
length = DSTR_SIZE;
|
||||
break;
|
||||
case TISS_TYPE:
|
||||
length = TISS_SIZE;
|
||||
break;
|
||||
case DPRS_TYPE:
|
||||
length = DPRS_SIZE;
|
||||
break;
|
||||
case SDPT_TYPE:
|
||||
length = SDPT_SIZE;
|
||||
break;
|
||||
case AIRS_TYPE:
|
||||
length = AIRS_SIZE;
|
||||
break;
|
||||
case DEND_TYPE:
|
||||
length = DEND_SIZE;
|
||||
break;
|
||||
default:
|
||||
ERROR (abstract->context, "Unknown record type (%08x).", type);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
if (offset + length > size) {
|
||||
ERROR (abstract->context, "Buffer overflow detected!");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned int etype = array_uint32_be(data + offset + length - 4);
|
||||
if (etype != type) {
|
||||
ERROR (abstract->context, "Invalid record end type (%08x).", etype);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
unsigned short crc = array_uint16_le(data + offset + length - 6);
|
||||
unsigned short ccrc = checksum_crc16_ccitt(data + offset + 4, length - 10, 0x0000, 0x0000);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Invalid record checksum (%04x %04x).", crc, ccrc);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
if (type == DPRS_TYPE || type == SDPT_TYPE) {
|
||||
unsigned int depth = 0, temperature = 0;
|
||||
unsigned int gasmix = 0, alarms = 0;
|
||||
unsigned int decostop = 0, decodepth = 0, decotime = 0, tts = 0;
|
||||
unsigned int bookmark = 0;
|
||||
if (type == SDPT_TYPE) {
|
||||
unsigned int misc = 0, deco = 0;
|
||||
depth = array_uint16_le (data + offset + marker + 2);
|
||||
temperature = array_uint16_le (data + offset + marker + 6);
|
||||
alarms = array_uint32_le (data + offset + marker + 0x14);
|
||||
misc = array_uint32_le (data + offset + marker + 0x18);
|
||||
deco = array_uint32_le (data + offset + marker + 0x1C);
|
||||
bookmark = (misc >> 2) & 0x0F;
|
||||
gasmix = (misc >> 6) & 0x0F;
|
||||
decostop = (misc >> 10) & 0x01;
|
||||
if (decostop) {
|
||||
decodepth = (deco >> 3) & 0x7F;
|
||||
decotime = (deco >> 10) & 0xFF;
|
||||
tts = (deco >> 18) & 0x3FFF;
|
||||
} else {
|
||||
decotime = deco & 0xFF;
|
||||
}
|
||||
} else {
|
||||
unsigned int misc = 0;
|
||||
depth = array_uint16_le (data + offset + marker + 0);
|
||||
temperature = array_uint16_le (data + offset + marker + 4);
|
||||
decotime = array_uint16_le (data + offset + marker + 0x0A);
|
||||
alarms = array_uint32_le (data + offset + marker + 0x0C);
|
||||
misc = array_uint32_le (data + offset + marker + 0x14);
|
||||
bookmark = (misc >> 2) & 0x0F;
|
||||
gasmix = (misc >> 6) & 0x0F;
|
||||
decostop = (misc >> 18) & 0x01;
|
||||
decodepth = (misc >> 19) & 0x7F;
|
||||
}
|
||||
|
||||
// Time (seconds).
|
||||
time += parser->interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Temperature (1/10 °C).
|
||||
sample.temperature = temperature / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
// Current gas mix
|
||||
if (parser->ngasmixes > 0) {
|
||||
if (gasmix >= parser->ngasmixes) {
|
||||
ERROR (abstract->context, "Invalid gas mix index.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
}
|
||||
|
||||
// Current tank
|
||||
tank = gasmix;
|
||||
|
||||
// Bookmark
|
||||
if (bookmark) {
|
||||
sample.event.type = SAMPLE_EVENT_BOOKMARK;
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = bookmark;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
// Deco stop / NDL.
|
||||
if (decostop) {
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = decodepth;
|
||||
} else {
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.depth = 0.0;
|
||||
}
|
||||
sample.deco.time = decotime * 60;
|
||||
sample.deco.tts = tts;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
|
||||
// Alarms
|
||||
for (unsigned int v = alarms, i = 0; v; v >>= 1, ++i) {
|
||||
if ((v & 1) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (i) {
|
||||
case ALARM_FAST_ASCENT:
|
||||
case ALARM_UNCONTROLLED_ASCENT:
|
||||
sample.event.type = SAMPLE_EVENT_ASCENT;
|
||||
break;
|
||||
case ALARM_MISSED_DECO:
|
||||
case ALARM_DIVE_VIOLATION_DECO:
|
||||
sample.event.type = SAMPLE_EVENT_CEILING;
|
||||
break;
|
||||
default:
|
||||
sample.event.type = SAMPLE_EVENT_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sample.event.type != SAMPLE_EVENT_NONE) {
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = 0;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
}
|
||||
} else if (type == AIRS_TYPE) {
|
||||
// Pressure (1/100 bar).
|
||||
unsigned int pressure = array_uint16_le(data + offset + marker + 0);
|
||||
if (tank < parser->ntanks) {
|
||||
sample.pressure.tank = tank;
|
||||
sample.pressure.value = pressure / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
} else if (pressure != 0) {
|
||||
WARNING (abstract->context, "Invalid tank with non-zero pressure.");
|
||||
}
|
||||
}
|
||||
|
||||
offset += length;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
|
||||
{
|
||||
mares_iconhd_parser_t *parser = (mares_iconhd_parser_t *) abstract;
|
||||
|
||||
// Cache the parser data.
|
||||
dc_status_t rc = mares_iconhd_parser_cache (parser);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
if (ISGENIUS(parser->model)) {
|
||||
return mares_genius_foreach (abstract, callback, userdata);
|
||||
} else {
|
||||
return mares_iconhd_foreach (abstract, callback, userdata);
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
mares_nemo_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
mares_nemo_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
mares_nemo_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -59,7 +59,6 @@ struct mares_nemo_parser_t {
|
||||
unsigned int extra;
|
||||
};
|
||||
|
||||
static dc_status_t mares_nemo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t mares_nemo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t mares_nemo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -67,7 +66,6 @@ static dc_status_t mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_
|
||||
static const dc_parser_vtable_t mares_nemo_parser_vtable = {
|
||||
sizeof(mares_nemo_parser_t),
|
||||
DC_FAMILY_MARES_NEMO,
|
||||
mares_nemo_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -79,15 +77,16 @@ static const dc_parser_vtable_t mares_nemo_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
mares_nemo_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
mares_nemo_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
mares_nemo_parser_t *parser = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (mares_nemo_parser_t *) dc_parser_allocate (context, &mares_nemo_parser_vtable);
|
||||
parser = (mares_nemo_parser_t *) dc_parser_allocate (context, &mares_nemo_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -98,70 +97,42 @@ mares_nemo_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int
|
||||
if (model == NEMOWIDE || model == NEMOAIR || model == PUCK || model == PUCKAIR)
|
||||
freedive = GAUGE;
|
||||
|
||||
// Set the default values.
|
||||
parser->model = model;
|
||||
parser->freedive = freedive;
|
||||
parser->mode = AIR;
|
||||
parser->length = 0;
|
||||
parser->sample_count = 0;
|
||||
parser->sample_size = 0;
|
||||
parser->header = 0;
|
||||
parser->extra = 0;
|
||||
|
||||
*out = (dc_parser_t*) parser;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
mares_nemo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
mares_nemo_parser_t *parser = (mares_nemo_parser_t *) abstract;
|
||||
|
||||
// Clear the previous state.
|
||||
parser->base.data = NULL;
|
||||
parser->base.size = 0;
|
||||
parser->mode = AIR;
|
||||
parser->length = 0;
|
||||
parser->sample_count = 0;
|
||||
parser->sample_size = 0;
|
||||
parser->header = 0;
|
||||
parser->extra = 0;
|
||||
|
||||
if (size == 0)
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
if (size < 2 + 3)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
if (size < 2 + 3) {
|
||||
status = DC_STATUS_DATAFORMAT;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
unsigned int length = array_uint16_le (data);
|
||||
if (length > size)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
if (length > size) {
|
||||
status = DC_STATUS_DATAFORMAT;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
unsigned int extra = 0;
|
||||
const unsigned char marker[3] = {0xAA, 0xBB, 0xCC};
|
||||
if (memcmp (data + length - 3, marker, sizeof (marker)) == 0) {
|
||||
if (parser->model == PUCKAIR)
|
||||
if (model == PUCKAIR)
|
||||
extra = 7;
|
||||
else
|
||||
extra = 12;
|
||||
}
|
||||
|
||||
if (length < 2 + extra + 3)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
if (length < 2 + extra + 3) {
|
||||
status = DC_STATUS_DATAFORMAT;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
unsigned int mode = data[length - extra - 1];
|
||||
|
||||
unsigned int header_size = 53;
|
||||
unsigned int sample_size = 2;
|
||||
if (extra) {
|
||||
if (parser->model == PUCKAIR)
|
||||
if (model == PUCKAIR)
|
||||
sample_size = 3;
|
||||
else
|
||||
sample_size = 5;
|
||||
}
|
||||
if (mode == parser->freedive) {
|
||||
if (mode == freedive) {
|
||||
header_size = 28;
|
||||
sample_size = 6;
|
||||
}
|
||||
@ -169,12 +140,14 @@ mares_nemo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, un
|
||||
unsigned int nsamples = array_uint16_le (data + length - extra - 3);
|
||||
|
||||
unsigned int nbytes = 2 + nsamples * sample_size + header_size + extra;
|
||||
if (length != nbytes)
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
if (length != nbytes) {
|
||||
status = DC_STATUS_DATAFORMAT;
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Store the new state.
|
||||
parser->base.data = data;
|
||||
parser->base.size = size;
|
||||
// Set the default values.
|
||||
parser->model = model;
|
||||
parser->freedive = freedive;
|
||||
parser->mode = mode;
|
||||
parser->length = length;
|
||||
parser->sample_count = nsamples;
|
||||
@ -182,7 +155,13 @@ mares_nemo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, un
|
||||
parser->header = header_size;
|
||||
parser->extra = extra;
|
||||
|
||||
*out = (dc_parser_t*) parser;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free:
|
||||
dc_parser_deallocate ((dc_parser_t *) parser);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@ -251,6 +230,7 @@ mares_nemo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
||||
}
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
break;
|
||||
case DC_FIELD_TANK_COUNT:
|
||||
if (parser->extra)
|
||||
@ -290,6 +270,7 @@ mares_nemo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
|
||||
} else {
|
||||
tank->gasmix = DC_GASMIX_UNKNOWN;
|
||||
}
|
||||
tank->usage = DC_USAGE_NONE;
|
||||
break;
|
||||
case DC_FIELD_TEMPERATURE_MINIMUM:
|
||||
*((double *) value) = (signed char) p[53 - 11];
|
||||
@ -382,17 +363,17 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
|
||||
// Time (seconds).
|
||||
time += 20;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Gas change.
|
||||
if (gasmix != gasmix_previous) {
|
||||
sample.gasmix = gasmix;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
@ -402,7 +383,7 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = ascent;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
// Deco violation
|
||||
@ -411,7 +392,7 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = 0;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
// Deco stop
|
||||
@ -422,20 +403,21 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
}
|
||||
sample.deco.time = 0;
|
||||
sample.deco.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
|
||||
// Pressure (1 bar).
|
||||
if (parser->sample_size == 3) {
|
||||
sample.pressure.tank = 0;
|
||||
sample.pressure.value = data[idx + 2];
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
} else if (parser->sample_size == 5) {
|
||||
unsigned int type = (time / 20) % 3;
|
||||
if (type == 0) {
|
||||
pressure -= data[idx + 2] * 100;
|
||||
sample.pressure.tank = 0;
|
||||
sample.pressure.value = pressure / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -459,12 +441,12 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
|
||||
// Surface Time (seconds).
|
||||
time += surftime;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Surface Depth (0 m).
|
||||
sample.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
if (profiles) {
|
||||
// Get the freedive sample interval for this model.
|
||||
@ -500,12 +482,12 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
time += interval;
|
||||
if (time > maxtime)
|
||||
time = maxtime; // Adjust the last sample.
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (1/10 m).
|
||||
sample.depth = depth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
}
|
||||
|
||||
// Verify that the number of samples in the profile data
|
||||
@ -519,12 +501,12 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
|
||||
} else {
|
||||
// Dive Time (seconds).
|
||||
time += divetime;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Maximum Depth (1/10 m).
|
||||
sample.depth = maxdepth / 10.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ dc_status_t
|
||||
mclean_extreme_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
mclean_extreme_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
mclean_extreme_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -58,7 +58,6 @@ struct mclean_extreme_parser_t {
|
||||
unsigned int gasmix[NGASMIXES];
|
||||
};
|
||||
|
||||
static dc_status_t mclean_extreme_parser_set_data(dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t mclean_extreme_parser_get_datetime(dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t mclean_extreme_parser_get_field(dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t mclean_extreme_parser_samples_foreach(dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -66,7 +65,6 @@ static dc_status_t mclean_extreme_parser_samples_foreach(dc_parser_t *abstract,
|
||||
static const dc_parser_vtable_t mclean_extreme_parser_vtable = {
|
||||
sizeof(mclean_extreme_parser_t),
|
||||
DC_FAMILY_MCLEAN_EXTREME,
|
||||
mclean_extreme_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -77,7 +75,7 @@ static const dc_parser_vtable_t mclean_extreme_parser_vtable = {
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
mclean_extreme_parser_create(dc_parser_t **out, dc_context_t *context)
|
||||
mclean_extreme_parser_create(dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
mclean_extreme_parser_t *parser = NULL;
|
||||
|
||||
@ -86,7 +84,7 @@ mclean_extreme_parser_create(dc_parser_t **out, dc_context_t *context)
|
||||
}
|
||||
|
||||
// Allocate memory.
|
||||
parser = (mclean_extreme_parser_t *)dc_parser_allocate(context, &mclean_extreme_parser_vtable);
|
||||
parser = (mclean_extreme_parser_t *)dc_parser_allocate(context, &mclean_extreme_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR(context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -104,21 +102,6 @@ mclean_extreme_parser_create(dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
mclean_extreme_parser_set_data(dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
mclean_extreme_parser_t *parser = (mclean_extreme_parser_t *)abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 0;
|
||||
parser->ngasmixes = 0;
|
||||
for (unsigned int i = 0; i < NGASMIXES; ++i) {
|
||||
parser->gasmix[i] = INVALID;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
mclean_extreme_parser_get_datetime(dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -221,6 +204,7 @@ mclean_extreme_parser_get_field(dc_parser_t *abstract, dc_field_type_t type, uns
|
||||
*((unsigned int *)value) = parser->ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.01 * abstract->data[0x0001 + 1 + 2 * parser->gasmix[flags]];
|
||||
gasmix->oxygen = 0.01 * abstract->data[0x0001 + 0 + 2 * parser->gasmix[flags]];
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -269,14 +253,14 @@ mclean_extreme_parser_samples_foreach(dc_parser_t *abstract, dc_sample_callback_
|
||||
const unsigned int setpoint = abstract->data[0x0013 + sp_index];
|
||||
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback(DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback(DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
sample.depth = 0.1 * depth;
|
||||
if (callback) callback(DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
sample.temperature = temperature;
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
if (gasmix_id != gasmix_previous) {
|
||||
// Find the gasmix in the list.
|
||||
@ -298,13 +282,13 @@ mclean_extreme_parser_samples_foreach(dc_parser_t *abstract, dc_sample_callback_
|
||||
}
|
||||
|
||||
sample.gasmix = idx;
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix_id;
|
||||
}
|
||||
|
||||
if (ccr) {
|
||||
sample.setpoint = 0.01 * setpoint;
|
||||
if (callback) callback(DC_SAMPLE_SETPOINT, sample, userdata);
|
||||
if (callback) callback(DC_SAMPLE_SETPOINT, &sample, userdata);
|
||||
}
|
||||
|
||||
offset += SZ_SAMPLE;
|
||||
|
||||
@ -86,6 +86,8 @@ static const oceanic_common_device_vtable_t oceanic_atom2_device_vtable = {
|
||||
NULL, /* timesync */
|
||||
oceanic_atom2_device_close /* close */
|
||||
},
|
||||
oceanic_common_device_devinfo,
|
||||
oceanic_common_device_pointers,
|
||||
oceanic_common_device_logbook,
|
||||
oceanic_common_device_profile,
|
||||
};
|
||||
@ -98,10 +100,11 @@ static const oceanic_common_layout_t aeris_f10_layout = {
|
||||
0x0100, /* rb_logbook_begin */
|
||||
0x0D80, /* rb_logbook_end */
|
||||
32, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0D80, /* rb_profile_begin */
|
||||
0x10000, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
2, /* pt_mode_logbook */
|
||||
3, /* pt_mode_logbook */
|
||||
0, /* pt_mode_serial */
|
||||
};
|
||||
|
||||
@ -113,10 +116,11 @@ static const oceanic_common_layout_t aeris_f11_layout = {
|
||||
0x0100, /* rb_logbook_begin */
|
||||
0x0D80, /* rb_logbook_end */
|
||||
32, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0D80, /* rb_profile_begin */
|
||||
0x20000, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
3, /* pt_mode_logbook */
|
||||
2, /* pt_mode_logbook */
|
||||
0, /* pt_mode_serial */
|
||||
};
|
||||
|
||||
@ -128,6 +132,7 @@ static const oceanic_common_layout_t oceanic_default_layout = {
|
||||
0x0240, /* rb_logbook_begin */
|
||||
0x0A40, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0A40, /* rb_profile_begin */
|
||||
0x10000, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -143,6 +148,7 @@ static const oceanic_common_layout_t oceanic_atom1_layout = {
|
||||
0x0240, /* rb_logbook_begin */
|
||||
0x0440, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0440, /* rb_profile_begin */
|
||||
0x8000, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -158,6 +164,7 @@ static const oceanic_common_layout_t oceanic_atom2a_layout = {
|
||||
0x0240, /* rb_logbook_begin */
|
||||
0x0A40, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0A40, /* rb_profile_begin */
|
||||
0xFE00, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -173,6 +180,7 @@ static const oceanic_common_layout_t oceanic_atom2b_layout = {
|
||||
0x0240, /* rb_logbook_begin */
|
||||
0x0A40, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0A40, /* rb_profile_begin */
|
||||
0xFE00, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -188,6 +196,7 @@ static const oceanic_common_layout_t oceanic_atom2c_layout = {
|
||||
0x0240, /* rb_logbook_begin */
|
||||
0x0A40, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0A40, /* rb_profile_begin */
|
||||
0xFFF0, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -203,6 +212,7 @@ static const oceanic_common_layout_t sherwood_wisdom_layout = {
|
||||
0x03D0, /* rb_logbook_begin */
|
||||
0x0A40, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0A40, /* rb_profile_begin */
|
||||
0xFE00, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -218,6 +228,7 @@ static const oceanic_common_layout_t oceanic_proplus3_layout = {
|
||||
0x03E0, /* rb_logbook_begin */
|
||||
0x0A40, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0A40, /* rb_profile_begin */
|
||||
0xFE00, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -233,6 +244,7 @@ static const oceanic_common_layout_t tusa_zenair_layout = {
|
||||
0x0240, /* rb_logbook_begin */
|
||||
0x0A40, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0A40, /* rb_profile_begin */
|
||||
0xFE00, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -248,6 +260,7 @@ static const oceanic_common_layout_t oceanic_oc1_layout = {
|
||||
0x0240, /* rb_logbook_begin */
|
||||
0x0A40, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0A40, /* rb_profile_begin */
|
||||
0x1FE00, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -263,6 +276,7 @@ static const oceanic_common_layout_t oceanic_oci_layout = {
|
||||
0x10C0, /* rb_logbook_begin */
|
||||
0x1400, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x1400, /* rb_profile_begin */
|
||||
0x1FE00, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -278,6 +292,7 @@ static const oceanic_common_layout_t oceanic_atom3_layout = {
|
||||
0x0400, /* rb_logbook_begin */
|
||||
0x0A40, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0A40, /* rb_profile_begin */
|
||||
0x1FE00, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -293,6 +308,7 @@ static const oceanic_common_layout_t oceanic_vt4_layout = {
|
||||
0x0420, /* rb_logbook_begin */
|
||||
0x0A40, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0A40, /* rb_profile_begin */
|
||||
0x1FE00, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -308,6 +324,7 @@ static const oceanic_common_layout_t hollis_tx1_layout = {
|
||||
0x0780, /* rb_logbook_begin */
|
||||
0x1000, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x1000, /* rb_profile_begin */
|
||||
0x40000, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -323,6 +340,7 @@ static const oceanic_common_layout_t oceanic_veo1_layout = {
|
||||
0x0400, /* rb_logbook_begin */
|
||||
0x0400, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0400, /* rb_profile_begin */
|
||||
0x0400, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -338,8 +356,9 @@ static const oceanic_common_layout_t oceanic_reactpro_layout = {
|
||||
0x0400, /* rb_logbook_begin */
|
||||
0x0600, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0600, /* rb_profile_begin */
|
||||
0xFFF0, /* rb_profile_end */
|
||||
0xFE00, /* rb_profile_end */
|
||||
1, /* pt_mode_global */
|
||||
1, /* pt_mode_logbook */
|
||||
0, /* pt_mode_serial */
|
||||
@ -353,6 +372,7 @@ static const oceanic_common_layout_t oceanic_proplusx_layout = {
|
||||
0x1000, /* rb_logbook_begin */
|
||||
0x10000, /* rb_logbook_end */
|
||||
16, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x40000, /* rb_profile_begin */
|
||||
0x440000, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -368,6 +388,7 @@ static const oceanic_common_layout_t aqualung_i770r_layout = {
|
||||
0x2000, /* rb_logbook_begin */
|
||||
0x10000, /* rb_logbook_end */
|
||||
16, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x40000, /* rb_profile_begin */
|
||||
0x640000, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -383,6 +404,7 @@ static const oceanic_common_layout_t aeris_a300cs_layout = {
|
||||
0x0900, /* rb_logbook_begin */
|
||||
0x1000, /* rb_logbook_end */
|
||||
16, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x1000, /* rb_profile_begin */
|
||||
0x3FE00, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -398,6 +420,7 @@ static const oceanic_common_layout_t aqualung_i450t_layout = {
|
||||
0x10C0, /* rb_logbook_begin */
|
||||
0x1400, /* rb_logbook_end */
|
||||
16, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x1400, /* rb_profile_begin */
|
||||
0x3FE00, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -415,13 +438,14 @@ static const oceanic_common_version_t versions[] = {
|
||||
{"MANTA R\0\0 512K", 0, MANTA, &oceanic_atom2c_layout},
|
||||
{"2M ATOM r\0\0 512K", 0x3349, ATOM2, &oceanic_atom2a_layout},
|
||||
{"2M ATOM r\0\0 512K", 0, ATOM2, &oceanic_atom2c_layout},
|
||||
{"OCE GEO R\0\0 512K", 0x3242, GEO, &oceanic_atom2a_layout},
|
||||
{"OCE GEO R\0\0 512K", 0, GEO, &oceanic_atom2c_layout},
|
||||
|
||||
{"INSIGHT2 \0\0 512K", 0, INSIGHT2, &oceanic_atom2a_layout},
|
||||
{"OCEVEO30 \0\0 512K", 0, VEO30, &oceanic_atom2a_layout},
|
||||
{"ATMOSAI R\0\0 512K", 0, ATMOSAI2, &oceanic_atom2a_layout},
|
||||
{"PROPLUS2 \0\0 512K", 0, PROPLUS21, &oceanic_atom2a_layout},
|
||||
{"OCEGEO20 \0\0 512K", 0, GEO20, &oceanic_atom2a_layout},
|
||||
{"OCE GEO R\0\0 512K", 0, GEO, &oceanic_atom2a_layout},
|
||||
{"AQUAI200 \0\0 512K", 0, I200, &oceanic_atom2a_layout},
|
||||
{"AQUA200C \0\0 512K", 0, I200C, &oceanic_atom2a_layout},
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@ dc_status_t
|
||||
oceanic_atom2_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
|
||||
|
||||
dc_status_t
|
||||
oceanic_atom2_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
oceanic_atom2_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -35,6 +35,12 @@
|
||||
#define GAUGE 1
|
||||
#define FREEDIVE 2
|
||||
|
||||
#define DSX_CC 0
|
||||
#define DSX_OC 1
|
||||
#define DSX_SIDEMOUNT 2
|
||||
#define DSX_SIDEGAUGE 3
|
||||
#define DSX_GAUGE 4
|
||||
|
||||
#define NGASMIXES 6
|
||||
|
||||
#define HEADER 1
|
||||
@ -45,6 +51,7 @@ typedef struct oceanic_atom2_parser_t oceanic_atom2_parser_t;
|
||||
struct oceanic_atom2_parser_t {
|
||||
dc_parser_t base;
|
||||
unsigned int model;
|
||||
unsigned int logbooksize;
|
||||
unsigned int headersize;
|
||||
unsigned int footersize;
|
||||
// Cached fields.
|
||||
@ -59,7 +66,6 @@ struct oceanic_atom2_parser_t {
|
||||
double maxdepth;
|
||||
};
|
||||
|
||||
static dc_status_t oceanic_atom2_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -67,7 +73,6 @@ static dc_status_t oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract,
|
||||
static const dc_parser_vtable_t oceanic_atom2_parser_vtable = {
|
||||
sizeof(oceanic_atom2_parser_t),
|
||||
DC_FAMILY_OCEANIC_ATOM2,
|
||||
oceanic_atom2_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -79,7 +84,7 @@ static const dc_parser_vtable_t oceanic_atom2_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
{
|
||||
oceanic_atom2_parser_t *parser = NULL;
|
||||
|
||||
@ -87,7 +92,7 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (oceanic_atom2_parser_t *) dc_parser_allocate (context, &oceanic_atom2_parser_vtable);
|
||||
parser = (oceanic_atom2_parser_t *) dc_parser_allocate (context, &oceanic_atom2_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -95,6 +100,7 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
|
||||
|
||||
// Set the default values.
|
||||
parser->model = model;
|
||||
parser->logbooksize = 0;
|
||||
parser->headersize = 9 * PAGESIZE / 2;
|
||||
parser->footersize = 2 * PAGESIZE / 2;
|
||||
if (model == DATAMASK || model == COMPUMASK ||
|
||||
@ -133,6 +139,14 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
|
||||
} else if (model == I550C || model == WISDOM4 ||
|
||||
model == I200CV2) {
|
||||
parser->headersize = 5 * PAGESIZE / 2;
|
||||
} else if (model == I330R) {
|
||||
parser->logbooksize = 64;
|
||||
parser->headersize = parser->logbooksize + 80;
|
||||
parser->footersize = 48;
|
||||
} else if (model == DSX) {
|
||||
parser->logbooksize = 512;
|
||||
parser->headersize = parser->logbooksize + 256;
|
||||
parser->footersize = 64;
|
||||
}
|
||||
|
||||
parser->cached = 0;
|
||||
@ -153,28 +167,6 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
oceanic_atom2_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
oceanic_atom2_parser_t *parser = (oceanic_atom2_parser_t *) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 0;
|
||||
parser->header = 0;
|
||||
parser->footer = 0;
|
||||
parser->mode = NORMAL;
|
||||
parser->ngasmixes = 0;
|
||||
for (unsigned int i = 0; i < NGASMIXES; ++i) {
|
||||
parser->oxygen[i] = 0;
|
||||
parser->helium[i] = 0;
|
||||
}
|
||||
parser->divetime = 0;
|
||||
parser->maxdepth = 0.0;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -194,8 +186,18 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim
|
||||
if (datetime) {
|
||||
// AM/PM bit of the 12-hour clock.
|
||||
unsigned int pm = p[1] & 0x80;
|
||||
unsigned int have_ampm = 1;
|
||||
|
||||
switch (parser->model) {
|
||||
case I330R:
|
||||
case DSX:
|
||||
datetime->year = p[7] + 2000;
|
||||
datetime->month = p[6];
|
||||
datetime->day = p[5];
|
||||
datetime->hour = p[3];
|
||||
datetime->minute = p[4];
|
||||
have_ampm = 0;
|
||||
break;
|
||||
case OC1A:
|
||||
case OC1B:
|
||||
case OC1C:
|
||||
@ -304,9 +306,11 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim
|
||||
datetime->timezone = DC_TIMEZONE_NONE;
|
||||
|
||||
// Convert to a 24-hour clock.
|
||||
datetime->hour %= 12;
|
||||
if (pm)
|
||||
datetime->hour += 12;
|
||||
if (have_ampm) {
|
||||
datetime->hour %= 12;
|
||||
if (pm)
|
||||
datetime->hour += 12;
|
||||
}
|
||||
|
||||
/*
|
||||
* Workaround for the year 2010 problem.
|
||||
@ -381,6 +385,10 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
|
||||
} else if (parser->model == VEO20 || parser->model == VEO30 ||
|
||||
parser->model == OCS) {
|
||||
mode = (data[1] & 0x60) >> 5;
|
||||
} else if (parser->model == I330R) {
|
||||
mode = data[2];
|
||||
} else if (parser->model == DSX) {
|
||||
mode = data[45];
|
||||
}
|
||||
|
||||
// Get the gas mixes.
|
||||
@ -438,6 +446,17 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
|
||||
} else if (parser->model == WISDOM4) {
|
||||
o2_offset = header + 4;
|
||||
ngasmixes = 1;
|
||||
} else if (parser->model == I330R) {
|
||||
ngasmixes = 3;
|
||||
o2_offset = parser->logbooksize + 16;
|
||||
} else if (parser->model == DSX) {
|
||||
if (mode < DSX_SIDEGAUGE) {
|
||||
o2_offset = parser->logbooksize + 0x89 + mode * 16;
|
||||
he_offset = parser->logbooksize + 0xB9 + mode * 16;
|
||||
ngasmixes = 6;
|
||||
} else {
|
||||
ngasmixes = 0;
|
||||
}
|
||||
} else {
|
||||
o2_offset = header + 4;
|
||||
ngasmixes = 3;
|
||||
@ -451,6 +470,10 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
|
||||
for (unsigned int i = 0; i < ngasmixes; ++i) {
|
||||
if (data[o2_offset + i * o2_step]) {
|
||||
parser->oxygen[i] = data[o2_offset + i * o2_step];
|
||||
// The i330R uses 20 as "Air" and 21 as 21% Nitrox
|
||||
if (parser->model == I330R && parser->oxygen[i] == 20) {
|
||||
parser->oxygen[i] = 21;
|
||||
}
|
||||
} else {
|
||||
parser->oxygen[i] = 21;
|
||||
}
|
||||
@ -509,13 +532,23 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
|
||||
parser->model == F11A || parser->model == F11B ||
|
||||
parser->model == MUNDIAL2 || parser->model == MUNDIAL3)
|
||||
*((double *) value) = array_uint16_le (data + 4) / 16.0 * FEET;
|
||||
else if (parser->model == I330R || parser->model == DSX)
|
||||
*((double *) value) = array_uint16_le (data + parser->footer + 10) / 10.0 * FEET;
|
||||
else
|
||||
*((double *) value) = (array_uint16_le (data + parser->footer + 4) & 0x0FFF) / 16.0 * FEET;
|
||||
break;
|
||||
case DC_FIELD_AVGDEPTH:
|
||||
if (parser->model == I330R || parser->model == DSX) {
|
||||
*((double *) value) = array_uint16_le (data + parser->footer + 12) / 10.0 * FEET;
|
||||
} else {
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->oxygen = parser->oxygen[flags] / 100.0;
|
||||
gasmix->helium = parser->helium[flags] / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -529,23 +562,49 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
|
||||
water->type = DC_WATER_SALT;
|
||||
}
|
||||
water->density = 0.0;
|
||||
} else if (parser->model == I330R || parser->model == DSX) {
|
||||
unsigned int settings = array_uint32_le (data + parser->logbooksize + 12);
|
||||
if (settings & 0x10000) {
|
||||
water->type = DC_WATER_FRESH;
|
||||
} else {
|
||||
water->type = DC_WATER_SALT;
|
||||
}
|
||||
water->density = 0.0;
|
||||
} else {
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_DIVEMODE:
|
||||
switch (parser->mode) {
|
||||
case NORMAL:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_OC;
|
||||
break;
|
||||
case GAUGE:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_GAUGE;
|
||||
break;
|
||||
case FREEDIVE:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_FREEDIVE;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
if (parser->model == DSX) {
|
||||
switch (parser->mode) {
|
||||
case DSX_OC:
|
||||
case DSX_SIDEMOUNT:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_OC;
|
||||
break;
|
||||
case DSX_SIDEGAUGE:
|
||||
case DSX_GAUGE:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_GAUGE;
|
||||
break;
|
||||
case DSX_CC:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_CCR;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
} else {
|
||||
switch (parser->mode) {
|
||||
case NORMAL:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_OC;
|
||||
break;
|
||||
case GAUGE:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_GAUGE;
|
||||
break;
|
||||
case FREEDIVE:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_FREEDIVE;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -586,7 +645,7 @@ oceanic_atom2_parser_vendor (oceanic_atom2_parser_t *parser, const unsigned char
|
||||
sample.vendor.type = SAMPLE_VENDOR_OCEANIC_ATOM2;
|
||||
sample.vendor.size = length;
|
||||
sample.vendor.data = data + offset;
|
||||
if (callback) callback (DC_SAMPLE_VENDOR, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_VENDOR, &sample, userdata);
|
||||
|
||||
offset += length;
|
||||
}
|
||||
@ -608,30 +667,25 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
|
||||
unsigned int extratime = 0;
|
||||
unsigned int time = 0;
|
||||
unsigned int interval = 1;
|
||||
unsigned int samplerate = 1;
|
||||
unsigned int interval = 1000;
|
||||
if (parser->mode != FREEDIVE) {
|
||||
unsigned int offset = 0x17;
|
||||
if (parser->model == A300CS || parser->model == VTX ||
|
||||
parser->model == I450T || parser->model == I750TC ||
|
||||
parser->model == PROPLUSX || parser->model == I770R ||
|
||||
parser->model == SAGE || parser->model == BEACON)
|
||||
offset = 0x1f;
|
||||
const unsigned int intervals[] = {2, 15, 30, 60};
|
||||
unsigned int idx = data[offset] & 0x03;
|
||||
interval = intervals[idx];
|
||||
if (parser->model == I330R || parser->model == DSX) {
|
||||
interval = data[parser->logbooksize + 36] * 1000;
|
||||
} else {
|
||||
unsigned int offset = 0x17;
|
||||
if (parser->model == A300CS || parser->model == VTX ||
|
||||
parser->model == I450T || parser->model == I750TC ||
|
||||
parser->model == PROPLUSX || parser->model == I770R ||
|
||||
parser->model == SAGE || parser->model == BEACON)
|
||||
offset = 0x1f;
|
||||
const unsigned int intervals[] = {2000, 15000, 30000, 60000};
|
||||
unsigned int idx = data[offset] & 0x03;
|
||||
interval = intervals[idx];
|
||||
}
|
||||
} else if (parser->model == F11A || parser->model == F11B) {
|
||||
const unsigned int intervals[] = {1, 1, 1, 2};
|
||||
const unsigned int samplerates[] = {4, 2, 1, 1};
|
||||
const unsigned int intervals[] = {250, 500, 1000, 2000};
|
||||
unsigned int idx = data[0x29] & 0x03;
|
||||
interval = intervals[idx];
|
||||
samplerate = samplerates[idx];
|
||||
if (samplerate > 1) {
|
||||
// Some models supports multiple samples per second.
|
||||
// Since our smallest unit of time is one second, we can't
|
||||
// represent this, and the extra samples will get dropped.
|
||||
WARNING(abstract->context, "Multiple samples per second are not supported!");
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int samplesize = PAGESIZE / 2;
|
||||
@ -650,8 +704,10 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
parser->model == I750TC || parser->model == PROPLUSX ||
|
||||
parser->model == I770R || parser->model == I470TC ||
|
||||
parser->model == SAGE || parser->model == BEACON ||
|
||||
parser->model == GEOAIR) {
|
||||
parser->model == GEOAIR || parser->model == I330R) {
|
||||
samplesize = PAGESIZE;
|
||||
} else if (parser->model == DSX) {
|
||||
samplesize = 32;
|
||||
}
|
||||
|
||||
unsigned int have_temperature = 1, have_pressure = 1;
|
||||
@ -666,7 +722,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
parser->model == I200 || parser->model == I100 ||
|
||||
parser->model == I300C || parser->model == TALIS ||
|
||||
parser->model == I200C || parser->model == I200CV2 ||
|
||||
parser->model == GEO40 || parser->model == VEO40) {
|
||||
parser->model == GEO40 || parser->model == VEO40 ||
|
||||
parser->model == I330R) {
|
||||
have_pressure = 0;
|
||||
}
|
||||
|
||||
@ -677,7 +734,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
}
|
||||
|
||||
// Initial tank pressure.
|
||||
unsigned int tank = 0;
|
||||
unsigned int tank = 1;
|
||||
unsigned int pressure = 0;
|
||||
if (have_pressure) {
|
||||
unsigned int idx = 2;
|
||||
@ -732,17 +789,17 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
if (sampletype == 0xAA) {
|
||||
if (parser->model == DATAMASK || parser->model == COMPUMASK) {
|
||||
// Tank pressure (1 psi) and number
|
||||
tank = 0;
|
||||
tank = 1;
|
||||
pressure = (((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF);
|
||||
} else if (parser->model == A300CS || parser->model == VTX ||
|
||||
parser->model == I750TC || parser->model == SAGE ||
|
||||
parser->model == BEACON) {
|
||||
// Tank pressure (1 psi) and number (one based index)
|
||||
tank = (data[offset + 1] & 0x03) - 1;
|
||||
tank = data[offset + 1] & 0x03;
|
||||
pressure = ((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF;
|
||||
} else {
|
||||
// Tank pressure (2 psi) and number (one based index)
|
||||
tank = (data[offset + 1] & 0x03) - 1;
|
||||
tank = data[offset + 1] & 0x03;
|
||||
if (parser->model == ATOM2 || parser->model == EPICA || parser->model == EPICB)
|
||||
pressure = (((data[offset + 3] << 8) + data[offset + 4]) & 0x0FFF) * 2;
|
||||
else
|
||||
@ -752,14 +809,14 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
// The surface time is not always a nice multiple of the samplerate.
|
||||
// The number of inserted surface samples is therefore rounded down
|
||||
// to keep the timestamps aligned at multiples of the samplerate.
|
||||
unsigned int surftime = 60 * bcd2dec (data[offset + 1]) + bcd2dec (data[offset + 2]);
|
||||
unsigned int surftime = (60 * bcd2dec (data[offset + 1]) + bcd2dec (data[offset + 2])) * 1000;
|
||||
unsigned int nsamples = surftime / interval;
|
||||
|
||||
for (unsigned int i = 0; i < nsamples; ++i) {
|
||||
// Time
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Vendor specific data
|
||||
if (i == 0) {
|
||||
@ -771,25 +828,18 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
|
||||
// Depth
|
||||
sample.depth = 0.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
complete = 1;
|
||||
}
|
||||
|
||||
extratime += surftime;
|
||||
} else {
|
||||
// Skip the extra samples.
|
||||
if ((count % samplerate) != 0) {
|
||||
offset += samplesize;
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Time.
|
||||
if (parser->model == I450T || parser->model == I470TC) {
|
||||
unsigned int minute = bcd2dec(data[offset + 0]);
|
||||
unsigned int hour = bcd2dec(data[offset + 1] & 0x0F);
|
||||
unsigned int second = bcd2dec(data[offset + 2]);
|
||||
unsigned int timestamp = (hour * 3600) + (minute * 60 ) + second + extratime;
|
||||
unsigned int timestamp = ((hour * 3600) + (minute * 60 ) + second) * 1000 + extratime;
|
||||
if (timestamp < time) {
|
||||
ERROR (abstract->context, "Timestamp moved backwards.");
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
@ -803,7 +853,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
time += interval;
|
||||
}
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Vendor specific data
|
||||
oceanic_atom2_parser_vendor (parser,
|
||||
@ -842,6 +892,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
parser->model == I770R|| parser->model == SAGE ||
|
||||
parser->model == BEACON) {
|
||||
temperature = data[offset + 11];
|
||||
} else if (parser->model == I330R || parser->model == DSX) {
|
||||
temperature = array_uint16_le(data + offset + 10);
|
||||
} else {
|
||||
unsigned int sign;
|
||||
if (parser->model == DG03 || parser->model == PROPLUS3 ||
|
||||
@ -864,8 +916,12 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
else
|
||||
temperature += (data[offset + 7] & 0x0C) >> 2;
|
||||
}
|
||||
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (parser->model == I330R || parser->model == DSX) {
|
||||
sample.temperature = ((temperature / 10.0) - 32.0) * (5.0 / 9.0);
|
||||
} else {
|
||||
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
||||
}
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
|
||||
// Tank Pressure (psi)
|
||||
@ -889,11 +945,17 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
parser->model == PROPLUSX || parser->model == I770R ||
|
||||
parser->model == SAGE || parser->model == BEACON)
|
||||
pressure = array_uint16_le (data + offset + 4);
|
||||
else
|
||||
else if (parser->model == DSX) {
|
||||
pressure = array_uint16_le (data + offset + 14);
|
||||
tank = (data[offset] & 0xF0) >> 4;
|
||||
} else {
|
||||
pressure -= data[offset + 1];
|
||||
sample.pressure.tank = tank;
|
||||
sample.pressure.value = pressure * PSI / BAR;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
|
||||
}
|
||||
if (tank) {
|
||||
sample.pressure.tank = tank - 1;
|
||||
sample.pressure.value = pressure * PSI / BAR;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
}
|
||||
}
|
||||
|
||||
// Depth (1/16 ft)
|
||||
@ -911,12 +973,18 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
parser->model == I470TC || parser->model == I200CV2 ||
|
||||
parser->model == GEOAIR)
|
||||
depth = (data[offset + 4] + (data[offset + 5] << 8)) & 0x0FFF;
|
||||
else if (parser->model == I330R || parser->model == DSX)
|
||||
depth = array_uint16_le (data + offset + 2);
|
||||
else if (parser->model == ATOM1)
|
||||
depth = data[offset + 3] * 16;
|
||||
else
|
||||
depth = (data[offset + 2] + (data[offset + 3] << 8)) & 0x0FFF;
|
||||
sample.depth = depth / 16.0 * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (parser->model == I330R || parser->model == DSX) {
|
||||
sample.depth = depth / 10.0 * FEET;
|
||||
} else {
|
||||
sample.depth = depth / 16.0 * FEET;
|
||||
}
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Gas mix
|
||||
unsigned int have_gasmix = 0;
|
||||
@ -924,14 +992,17 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
if (parser->model == TX1) {
|
||||
gasmix = data[offset] & 0x07;
|
||||
have_gasmix = 1;
|
||||
} else if (parser->model == DSX) {
|
||||
gasmix = (data[offset] & 0xF0) >> 4;
|
||||
have_gasmix = 1;
|
||||
}
|
||||
if (have_gasmix && gasmix != gasmix_previous) {
|
||||
if (have_gasmix && gasmix != gasmix_previous && parser->ngasmixes > 0) {
|
||||
if (gasmix < 1 || gasmix > parser->ngasmixes) {
|
||||
ERROR (abstract->context, "Invalid gas mix index (%u).", gasmix);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
sample.gasmix = gasmix - 1;
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
|
||||
gasmix_previous = gasmix;
|
||||
}
|
||||
|
||||
@ -955,7 +1026,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
have_deco = 1;
|
||||
} else if (parser->model == ATOM31 || parser->model == VISION ||
|
||||
parser->model == XPAIR || parser->model == I550 ||
|
||||
parser->model == I550C || parser->model == WISDOM4) {
|
||||
parser->model == I550C || parser->model == WISDOM4 ||
|
||||
parser->model == PROPLUS4 || parser->model == ATMOSAI2) {
|
||||
decostop = (data[offset + 5] & 0xF0) >> 4;
|
||||
decotime = array_uint16_le(data + offset + 4) & 0x03FF;
|
||||
have_deco = 1;
|
||||
@ -970,17 +1042,32 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
decostop = (data[offset + 7] & 0xF0) >> 4;
|
||||
decotime = array_uint16_le(data + offset + 6) & 0x0FFF;
|
||||
have_deco = 1;
|
||||
} else if (parser->model == I330R || parser->model == DSX) {
|
||||
decostop = data[offset + 8];
|
||||
if (decostop) {
|
||||
// Deco time
|
||||
decotime = array_uint16_le(data + offset + 6);
|
||||
} else {
|
||||
// NDL
|
||||
decotime = array_uint16_le(data + offset + 4);
|
||||
}
|
||||
have_deco = 1;
|
||||
}
|
||||
if (have_deco) {
|
||||
if (decostop) {
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.depth = decostop * 10 * FEET;
|
||||
if (parser->model == I330R || parser->model == DSX) {
|
||||
sample.deco.depth = decostop * FEET;
|
||||
} else {
|
||||
sample.deco.depth = decostop * 10 * FEET;
|
||||
}
|
||||
} else {
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.depth = 0.0;
|
||||
}
|
||||
sample.deco.time = decotime * 60;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
}
|
||||
|
||||
unsigned int have_rbt = 0;
|
||||
@ -997,13 +1084,21 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
have_rbt = 1;
|
||||
} else if (parser->model == VISION || parser->model == XPAIR ||
|
||||
parser->model == I550 || parser->model == I550C ||
|
||||
parser->model == WISDOM4) {
|
||||
parser->model == WISDOM4 || parser->model == PROPLUS4 ||
|
||||
parser->model == ATMOSAI2) {
|
||||
rbt = array_uint16_le(data + offset + 6) & 0x03FF;
|
||||
have_rbt = 1;
|
||||
}
|
||||
if (have_rbt) {
|
||||
sample.rbt = rbt;
|
||||
if (callback) callback (DC_SAMPLE_RBT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_RBT, &sample, userdata);
|
||||
}
|
||||
|
||||
// PPO2
|
||||
if (parser->model == I330R) {
|
||||
sample.ppo2.sensor = DC_SENSOR_NONE;
|
||||
sample.ppo2.value = data[offset + 9] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PPO2, &sample, userdata);
|
||||
}
|
||||
|
||||
// Bookmarks
|
||||
@ -1018,7 +1113,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
sample.event.time = 0;
|
||||
sample.event.flags = 0;
|
||||
sample.event.value = 0;
|
||||
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata);
|
||||
}
|
||||
|
||||
count++;
|
||||
|
||||
@ -32,72 +32,62 @@
|
||||
|
||||
#define VTABLE(abstract) ((const oceanic_common_device_vtable_t *) abstract->vtable)
|
||||
|
||||
#define RB_LOGBOOK_DISTANCE(a,b,l) ringbuffer_distance (a, b, 1, l->rb_logbook_begin, l->rb_logbook_end)
|
||||
#define RB_LOGBOOK_INCR(a,b,l) ringbuffer_increment (a, b, l->rb_logbook_begin, l->rb_logbook_end)
|
||||
#define RB_LOGBOOK_DISTANCE(a,b,l,m) ringbuffer_distance (a, b, m, l->rb_logbook_begin, l->rb_logbook_end)
|
||||
|
||||
#define RB_PROFILE_DISTANCE(a,b,l) ringbuffer_distance (a, b, 0, l->rb_profile_begin, l->rb_profile_end)
|
||||
#define RB_PROFILE_INCR(a,b,l) ringbuffer_increment (a, b, l->rb_profile_begin, l->rb_profile_end)
|
||||
#define RB_PROFILE_DISTANCE(a,b,l,m) ringbuffer_distance (a, b, m, l->rb_profile_begin, l->rb_profile_end)
|
||||
|
||||
#define INVALID 0
|
||||
|
||||
static unsigned int
|
||||
get_profile_first (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int pagesize)
|
||||
static dc_status_t
|
||||
oceanic_common_device_get_profile (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int *begin, unsigned int *end)
|
||||
{
|
||||
unsigned int value;
|
||||
assert (layout != NULL);
|
||||
assert (begin != NULL && end != NULL);
|
||||
|
||||
// Get the pagesize
|
||||
unsigned int pagesize = layout->highmem ? 16 * PAGESIZE : PAGESIZE;
|
||||
|
||||
// Get the profile pointers.
|
||||
unsigned int first = 0, last = 0;
|
||||
if (layout->pt_mode_logbook == 0) {
|
||||
value = array_uint16_le (data + 5);
|
||||
first = array_uint16_le (data + 5);
|
||||
last = array_uint16_le (data + 6) >> 4;
|
||||
} else if (layout->pt_mode_logbook == 1) {
|
||||
value = array_uint16_le (data + 4);
|
||||
} else if (layout->pt_mode_logbook == 3) {
|
||||
value = array_uint16_le (data + 16);
|
||||
} else {
|
||||
return array_uint16_le (data + 16);
|
||||
first = array_uint16_le (data + 4);
|
||||
last = array_uint16_le (data + 6);
|
||||
} else if (layout->pt_mode_logbook == 2 || layout->pt_mode_logbook == 3) {
|
||||
first = array_uint16_le (data + 16);
|
||||
last = array_uint16_le (data + 18);
|
||||
} else if (layout->pt_mode_logbook == 4) {
|
||||
first = array_uint32_le (data + 8);
|
||||
last = array_uint32_le (data + 12);
|
||||
}
|
||||
|
||||
unsigned int npages = (layout->memsize - layout->highmem) / pagesize;
|
||||
if (npages > 0x4000) {
|
||||
value &= 0x7FFF;
|
||||
} else if (npages > 0x2000) {
|
||||
value &= 0x3FFF;
|
||||
} else if (npages > 0x1000) {
|
||||
value &= 0x1FFF;
|
||||
} else {
|
||||
value &= 0x0FFF;
|
||||
// Convert pages to bytes.
|
||||
if (layout->pt_mode_logbook < 3) {
|
||||
unsigned int npages = (layout->memsize - layout->highmem) / pagesize;
|
||||
if (npages > 0x4000) {
|
||||
first &= 0x7FFF;
|
||||
last &= 0x7FFF;
|
||||
} else if (npages > 0x2000) {
|
||||
first &= 0x3FFF;
|
||||
last &= 0x3FFF;
|
||||
} else if (npages > 0x1000) {
|
||||
first &= 0x1FFF;
|
||||
last &= 0x1FFF;
|
||||
} else {
|
||||
first &= 0x0FFF;
|
||||
last &= 0x0FFF;
|
||||
}
|
||||
|
||||
first *= pagesize;
|
||||
last *= pagesize;
|
||||
}
|
||||
|
||||
return layout->highmem + value * pagesize;
|
||||
}
|
||||
*begin = layout->highmem + first;
|
||||
*end = layout->highmem + last + (layout->pt_mode_logbook < 4 ? pagesize : 0);
|
||||
|
||||
|
||||
static unsigned int
|
||||
get_profile_last (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int pagesize)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
if (layout->pt_mode_logbook == 0) {
|
||||
value = array_uint16_le (data + 6) >> 4;
|
||||
} else if (layout->pt_mode_logbook == 1) {
|
||||
value = array_uint16_le (data + 6);
|
||||
} else if (layout->pt_mode_logbook == 3) {
|
||||
value = array_uint16_le (data + 18);
|
||||
} else {
|
||||
return array_uint16_le(data + 18);
|
||||
}
|
||||
|
||||
unsigned int npages = (layout->memsize - layout->highmem) / pagesize;
|
||||
|
||||
if (npages > 0x4000) {
|
||||
value &= 0x7FFF;
|
||||
} else if (npages > 0x2000) {
|
||||
value &= 0x3FFF;
|
||||
} else if (npages > 0x1000) {
|
||||
value &= 0x1FFF;
|
||||
} else {
|
||||
value &= 0x0FFF;
|
||||
}
|
||||
|
||||
return layout->highmem + value * pagesize;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@ -206,11 +196,11 @@ oceanic_common_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Emit a vendor event.
|
||||
dc_event_vendor_t vendor;
|
||||
vendor.data = device->version;
|
||||
vendor.size = sizeof (device->version);
|
||||
device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
|
||||
// Read the device info.
|
||||
status = VTABLE(abstract)->devinfo (abstract, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Download the memory dump.
|
||||
status = device_dump_read (abstract, 0, dc_buffer_get_data (buffer),
|
||||
@ -219,8 +209,43 @@ oceanic_common_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
dc_status_t
|
||||
oceanic_common_device_devinfo (dc_device_t *abstract, dc_event_progress_t *progress)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
oceanic_common_device_t *device = (oceanic_common_device_t *) abstract;
|
||||
|
||||
assert (device != NULL);
|
||||
assert (device->layout != NULL);
|
||||
|
||||
const oceanic_common_layout_t *layout = device->layout;
|
||||
|
||||
// Read the device id.
|
||||
unsigned char id[PAGESIZE] = {0};
|
||||
status = dc_device_read (abstract, layout->cf_devinfo, id, sizeof (id));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the memory page.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
if (progress) {
|
||||
progress->current += PAGESIZE;
|
||||
progress->maximum += PAGESIZE;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
|
||||
}
|
||||
|
||||
// Emit a vendor event.
|
||||
dc_event_vendor_t vendor;
|
||||
vendor.data = device->version;
|
||||
vendor.size = sizeof (device->version);
|
||||
device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
|
||||
|
||||
// Emit a device info event.
|
||||
unsigned char *id = dc_buffer_get_data (buffer) + layout->cf_devinfo;
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = array_uint16_be (id + 8);
|
||||
devinfo.firmware = device->firmware;
|
||||
@ -240,7 +265,51 @@ oceanic_common_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
|
||||
|
||||
|
||||
dc_status_t
|
||||
oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook)
|
||||
oceanic_common_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress,
|
||||
unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end,
|
||||
unsigned int *rb_profile_begin, unsigned int *rb_profile_end)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
oceanic_common_device_t *device = (oceanic_common_device_t *) abstract;
|
||||
|
||||
assert (device != NULL);
|
||||
assert (device->layout != NULL);
|
||||
assert (rb_logbook_begin != NULL && rb_logbook_end != NULL);
|
||||
assert (rb_profile_begin != NULL && rb_profile_end != NULL);
|
||||
|
||||
const oceanic_common_layout_t *layout = device->layout;
|
||||
|
||||
// Read the pointer data.
|
||||
unsigned char pointers[PAGESIZE] = {0};
|
||||
status = dc_device_read (abstract, layout->cf_pointers, pointers, sizeof (pointers));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the memory page.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
if (progress) {
|
||||
progress->current += PAGESIZE;
|
||||
progress->maximum += PAGESIZE;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
|
||||
}
|
||||
|
||||
// Get the pointers.
|
||||
unsigned int rb_logbook_first = array_uint16_le (pointers + 4);
|
||||
unsigned int rb_logbook_last = array_uint16_le (pointers + 6);
|
||||
unsigned int rb_profile_first = array_uint16_le (pointers + 8);
|
||||
unsigned int rb_profile_last = array_uint16_le (pointers + 10);
|
||||
|
||||
*rb_logbook_begin = rb_logbook_first;
|
||||
*rb_logbook_end = rb_logbook_last + (layout->pt_mode_global == 0 ? layout->rb_logbook_entry_size : 0);
|
||||
*rb_profile_begin = rb_profile_first;
|
||||
*rb_profile_end = rb_profile_last;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end)
|
||||
{
|
||||
oceanic_common_device_t *device = (oceanic_common_device_t *) abstract;
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
@ -256,37 +325,30 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr
|
||||
if (!dc_buffer_clear (logbook))
|
||||
return DC_STATUS_NOMEMORY;
|
||||
|
||||
// For devices without a logbook ringbuffer, downloading dives isn't
|
||||
// possible. This is not considered a fatal error, but handled as if there
|
||||
// are no dives present.
|
||||
if (layout->rb_logbook_begin == layout->rb_logbook_end) {
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Read the pointer data.
|
||||
unsigned char pointers[PAGESIZE] = {0};
|
||||
rc = dc_device_read (abstract, layout->cf_pointers, pointers, sizeof (pointers));
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the memory page.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Get the logbook pointers.
|
||||
unsigned int rb_logbook_first = array_uint16_le (pointers + 4);
|
||||
unsigned int rb_logbook_last = array_uint16_le (pointers + 6);
|
||||
if (rb_logbook_last < layout->rb_logbook_begin ||
|
||||
rb_logbook_last >= layout->rb_logbook_end)
|
||||
// Validate the logbook pointers.
|
||||
unsigned int rb_logbook_begin = begin;
|
||||
unsigned int rb_logbook_end = end;
|
||||
if (rb_logbook_begin < layout->rb_logbook_begin ||
|
||||
rb_logbook_begin > layout->rb_logbook_end)
|
||||
{
|
||||
ERROR (abstract->context, "Invalid logbook end pointer detected (0x%04x).", rb_logbook_last);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
ERROR (abstract->context, "Invalid logbook begin pointer detected (0x%04x).", rb_logbook_begin);
|
||||
if (layout->rb_logbook_direction == 0) {
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
// Fall back to downloading the entire logbook ringbuffer as
|
||||
// workaround for an invalid logbook begin pointer!
|
||||
rb_logbook_begin = rb_logbook_end;
|
||||
}
|
||||
|
||||
// Calculate the end pointer.
|
||||
unsigned int rb_logbook_end = 0;
|
||||
if (layout->pt_mode_global == 0) {
|
||||
rb_logbook_end = RB_LOGBOOK_INCR (rb_logbook_last, layout->rb_logbook_entry_size, layout);
|
||||
} else {
|
||||
rb_logbook_end = rb_logbook_last;
|
||||
if (rb_logbook_end < layout->rb_logbook_begin ||
|
||||
rb_logbook_end > layout->rb_logbook_end)
|
||||
{
|
||||
ERROR (abstract->context, "Invalid logbook end pointer detected (0x%04x).", rb_logbook_end);
|
||||
if (layout->rb_logbook_direction != 0) {
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
// Fall back to downloading the entire logbook ringbuffer as
|
||||
// workaround for an invalid logbook end pointer!
|
||||
rb_logbook_end = rb_logbook_begin;
|
||||
}
|
||||
|
||||
// Calculate the number of bytes.
|
||||
@ -295,21 +357,9 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr
|
||||
// full ringbuffer. We always consider the ringbuffer full in that
|
||||
// case, because an empty ringbuffer can be detected by inspecting
|
||||
// the logbook entries once they are downloaded.
|
||||
unsigned int rb_logbook_size = 0;
|
||||
if (rb_logbook_first < layout->rb_logbook_begin ||
|
||||
rb_logbook_first >= layout->rb_logbook_end)
|
||||
{
|
||||
// Fall back to downloading the entire logbook ringbuffer as
|
||||
// workaround for an invalid logbook begin pointer!
|
||||
ERROR (abstract->context, "Invalid logbook begin pointer detected (0x%04x).", rb_logbook_first);
|
||||
rb_logbook_size = layout->rb_logbook_end - layout->rb_logbook_begin;
|
||||
} else {
|
||||
rb_logbook_size = RB_LOGBOOK_DISTANCE (rb_logbook_first, rb_logbook_end, layout);
|
||||
}
|
||||
unsigned int rb_logbook_size = RB_LOGBOOK_DISTANCE (rb_logbook_begin, rb_logbook_end, layout, DC_RINGBUFFER_FULL);
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress->current += PAGESIZE;
|
||||
progress->maximum += PAGESIZE;
|
||||
progress->maximum -= (layout->rb_logbook_end - layout->rb_logbook_begin) - rb_logbook_size;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
|
||||
|
||||
@ -327,7 +377,11 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
dc_rbstream_t *rbstream = NULL;
|
||||
rc = dc_rbstream_new (&rbstream, abstract, PAGESIZE, PAGESIZE * device->multipage, layout->rb_logbook_begin, layout->rb_logbook_end, rb_logbook_end);
|
||||
rc = dc_rbstream_new (&rbstream, abstract,
|
||||
PAGESIZE, PAGESIZE * device->multipage,
|
||||
layout->rb_logbook_begin, layout->rb_logbook_end,
|
||||
layout->rb_logbook_direction ? rb_logbook_end : rb_logbook_begin,
|
||||
layout->rb_logbook_direction ? DC_RBSTREAM_BACKWARD : DC_RBSTREAM_FORWARD);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
return rc;
|
||||
@ -403,9 +457,6 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
|
||||
|
||||
const oceanic_common_layout_t *layout = device->layout;
|
||||
|
||||
// Get the pagesize
|
||||
unsigned int pagesize = layout->highmem ? 16 * PAGESIZE : PAGESIZE;
|
||||
|
||||
// Cache the logbook pointer and size.
|
||||
const unsigned char *logbooks = dc_buffer_get_data (logbook);
|
||||
unsigned int rb_logbook_size = dc_buffer_get_size (logbook);
|
||||
@ -413,6 +464,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
|
||||
// Go through the logbook entries a first time, to get the end of
|
||||
// profile pointer and calculate the total amount of bytes in the
|
||||
// profile ringbuffer.
|
||||
unsigned int rb_profile_begin = INVALID;
|
||||
unsigned int rb_profile_end = INVALID;
|
||||
unsigned int rb_profile_size = 0;
|
||||
|
||||
@ -434,22 +486,20 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
|
||||
}
|
||||
|
||||
// Get the profile pointers.
|
||||
unsigned int rb_entry_first = get_profile_first (logbooks + entry, layout, pagesize);
|
||||
unsigned int rb_entry_last = get_profile_last (logbooks + entry, layout, pagesize);
|
||||
if (rb_entry_first < layout->rb_profile_begin ||
|
||||
rb_entry_first >= layout->rb_profile_end ||
|
||||
rb_entry_last < layout->rb_profile_begin ||
|
||||
rb_entry_last >= layout->rb_profile_end)
|
||||
unsigned int rb_entry_begin = 0, rb_entry_end = 0;
|
||||
oceanic_common_device_get_profile (logbooks + entry, layout, &rb_entry_begin, &rb_entry_end);
|
||||
if (rb_entry_begin < layout->rb_profile_begin ||
|
||||
rb_entry_begin > layout->rb_profile_end ||
|
||||
rb_entry_end < layout->rb_profile_begin ||
|
||||
rb_entry_end > layout->rb_profile_end)
|
||||
{
|
||||
ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).",
|
||||
rb_entry_first, rb_entry_last);
|
||||
rb_entry_begin, rb_entry_end);
|
||||
status = DC_STATUS_DATAFORMAT;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calculate the end pointer and the number of bytes.
|
||||
unsigned int rb_entry_end = RB_PROFILE_INCR (rb_entry_last, pagesize, layout);
|
||||
unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_first, rb_entry_last, layout) + pagesize;
|
||||
DEBUG (abstract->context, "Entry: %08x %08x", rb_entry_begin, rb_entry_end);
|
||||
|
||||
// Take the end pointer of the most recent logbook entry as the
|
||||
// end of profile pointer.
|
||||
@ -457,11 +507,13 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
|
||||
rb_profile_end = previous = rb_entry_end;
|
||||
}
|
||||
|
||||
// Calculate the number of bytes.
|
||||
unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_begin, rb_entry_end, layout, DC_RINGBUFFER_FULL);
|
||||
|
||||
// Skip gaps between the profiles.
|
||||
unsigned int gap = 0;
|
||||
if (rb_entry_end != previous) {
|
||||
WARNING (abstract->context, "Profiles are not continuous.");
|
||||
gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout);
|
||||
unsigned int gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout, DC_RINGBUFFER_EMPTY);
|
||||
if (gap) {
|
||||
WARNING (abstract->context, "Profiles are not continuous (%u bytes).", gap);
|
||||
}
|
||||
|
||||
// Make sure the profile size is valid.
|
||||
@ -470,13 +522,18 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
|
||||
break;
|
||||
}
|
||||
|
||||
// Update the profile begin pointer.
|
||||
rb_profile_begin = rb_entry_begin;
|
||||
|
||||
// Update the total profile size.
|
||||
rb_profile_size += rb_entry_size + gap;
|
||||
|
||||
remaining -= rb_entry_size + gap;
|
||||
previous = rb_entry_first;
|
||||
previous = rb_entry_begin;
|
||||
}
|
||||
|
||||
DEBUG (abstract->context, "Profile: %08x %08x", rb_profile_begin, rb_profile_end);
|
||||
|
||||
// At this point, we know the exact amount of data
|
||||
// that needs to be transfered for the profiles.
|
||||
progress->maximum -= (layout->rb_profile_end - layout->rb_profile_begin) - rb_profile_size;
|
||||
@ -489,7 +546,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
dc_rbstream_t *rbstream = NULL;
|
||||
rc = dc_rbstream_new (&rbstream, abstract, PAGESIZE, PAGESIZE * device->multipage, layout->rb_profile_begin, layout->rb_profile_end, rb_profile_end);
|
||||
rc = dc_rbstream_new (&rbstream, abstract, PAGESIZE, PAGESIZE * device->multipage, layout->rb_profile_begin, layout->rb_profile_end, rb_profile_end, DC_RBSTREAM_BACKWARD);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
return rc;
|
||||
@ -524,28 +581,28 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
|
||||
}
|
||||
|
||||
// Get the profile pointers.
|
||||
unsigned int rb_entry_first = get_profile_first (logbooks + entry, layout, pagesize);
|
||||
unsigned int rb_entry_last = get_profile_last (logbooks + entry, layout, pagesize);
|
||||
if (rb_entry_first < layout->rb_profile_begin ||
|
||||
rb_entry_first >= layout->rb_profile_end ||
|
||||
rb_entry_last < layout->rb_profile_begin ||
|
||||
rb_entry_last >= layout->rb_profile_end)
|
||||
unsigned int rb_entry_begin = 0, rb_entry_end = 0;
|
||||
oceanic_common_device_get_profile (logbooks + entry, layout, &rb_entry_begin, &rb_entry_end);
|
||||
if (rb_entry_begin < layout->rb_profile_begin ||
|
||||
rb_entry_begin > layout->rb_profile_end ||
|
||||
rb_entry_end < layout->rb_profile_begin ||
|
||||
rb_entry_end > layout->rb_profile_end)
|
||||
{
|
||||
ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).",
|
||||
rb_entry_first, rb_entry_last);
|
||||
rb_entry_begin, rb_entry_end);
|
||||
status = DC_STATUS_DATAFORMAT;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calculate the end pointer and the number of bytes.
|
||||
unsigned int rb_entry_end = RB_PROFILE_INCR (rb_entry_last, pagesize, layout);
|
||||
unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_first, rb_entry_last, layout) + pagesize;
|
||||
DEBUG (abstract->context, "Entry: %08x %08x", rb_entry_begin, rb_entry_end);
|
||||
|
||||
// Calculate the number of bytes.
|
||||
unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_begin, rb_entry_end, layout, DC_RINGBUFFER_FULL);
|
||||
|
||||
// Skip gaps between the profiles.
|
||||
unsigned int gap = 0;
|
||||
if (rb_entry_end != previous) {
|
||||
WARNING (abstract->context, "Profiles are not continuous.");
|
||||
gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout);
|
||||
unsigned int gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout, DC_RINGBUFFER_EMPTY);
|
||||
if (gap) {
|
||||
WARNING (abstract->context, "Profiles are not continuous (%u bytes).", gap);
|
||||
}
|
||||
|
||||
// Make sure the profile size is valid.
|
||||
@ -566,7 +623,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
|
||||
}
|
||||
|
||||
remaining -= rb_entry_size + gap;
|
||||
previous = rb_entry_first;
|
||||
previous = rb_entry_begin;
|
||||
|
||||
// Prepend the logbook entry to the profile data. The memory buffer is
|
||||
// large enough to store this entry.
|
||||
@ -604,6 +661,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
|
||||
dc_status_t
|
||||
oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
oceanic_common_device_t *device = (oceanic_common_device_t *) abstract;
|
||||
|
||||
assert (device != NULL);
|
||||
@ -611,45 +669,37 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
|
||||
|
||||
const oceanic_common_layout_t *layout = device->layout;
|
||||
|
||||
// For devices without a logbook and profile ringbuffer, downloading dives
|
||||
// isn't possible. This is not considered a fatal error, but handled as if
|
||||
// there are no dives present.
|
||||
if (layout->rb_logbook_begin == layout->rb_logbook_end &&
|
||||
layout->rb_profile_begin == layout->rb_profile_end) {
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Enable progress notifications.
|
||||
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
|
||||
progress.maximum = PAGESIZE +
|
||||
progress.maximum =
|
||||
(layout->rb_logbook_end - layout->rb_logbook_begin) +
|
||||
(layout->rb_profile_end - layout->rb_profile_begin);
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
|
||||
// Emit a vendor event.
|
||||
dc_event_vendor_t vendor;
|
||||
vendor.data = device->version;
|
||||
vendor.size = sizeof (device->version);
|
||||
device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
|
||||
|
||||
// Read the device id.
|
||||
unsigned char id[PAGESIZE] = {0};
|
||||
dc_status_t rc = dc_device_read (abstract, layout->cf_devinfo, id, sizeof (id));
|
||||
// Read the device info.
|
||||
rc = VTABLE(abstract)->devinfo (abstract, &progress);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the memory page.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress.current += PAGESIZE;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
|
||||
// Read the ringbuffer pointers.
|
||||
unsigned int rb_logbook_begin = 0, rb_logbook_end = 0;
|
||||
unsigned int rb_profile_begin = 0, rb_profile_end = 0;
|
||||
rc = VTABLE(abstract)->pointers (abstract, &progress, &rb_logbook_begin, &rb_logbook_end, &rb_profile_begin, &rb_profile_end);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = array_uint16_be (id + 8);
|
||||
devinfo.firmware = device->firmware;
|
||||
if (layout->pt_mode_serial == 0)
|
||||
devinfo.serial = array_convert_bcd2dec (id + 10, 3);
|
||||
else if (layout->pt_mode_serial == 1)
|
||||
devinfo.serial = array_convert_bin2dec (id + 11, 3);
|
||||
else
|
||||
devinfo.serial =
|
||||
(id[11] & 0x0F) * 100000 + ((id[11] & 0xF0) >> 4) * 10000 +
|
||||
(id[12] & 0x0F) * 1000 + ((id[12] & 0xF0) >> 4) * 100 +
|
||||
(id[13] & 0x0F) * 10 + ((id[13] & 0xF0) >> 4) * 1;
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
DEBUG (abstract->context, "Logbook: %08x %08x", rb_logbook_begin, rb_logbook_end);
|
||||
DEBUG (abstract->context, "Profile: %08x %08x", rb_profile_begin, rb_profile_end);
|
||||
|
||||
// Memory buffer for the logbook data.
|
||||
dc_buffer_t *logbook = dc_buffer_new (0);
|
||||
@ -658,7 +708,7 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
|
||||
}
|
||||
|
||||
// Download the logbook ringbuffer.
|
||||
rc = VTABLE(abstract)->logbook (abstract, &progress, logbook);
|
||||
rc = VTABLE(abstract)->logbook (abstract, &progress, logbook, rb_logbook_begin, rb_logbook_end);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
dc_buffer_free (logbook);
|
||||
return rc;
|
||||
|
||||
@ -125,8 +125,12 @@ extern "C" {
|
||||
#define I200CV2 0x4749
|
||||
#define GEOAIR 0x474B
|
||||
|
||||
// i330r
|
||||
#define DSX 0x4741
|
||||
#define I330R 0x4744
|
||||
|
||||
#define PAGESIZE 0x10
|
||||
#define FPMAXSIZE 0x20
|
||||
#define FPMAXSIZE 0x200
|
||||
|
||||
#define OCEANIC_COMMON_MATCH(version,patterns,firmware) \
|
||||
oceanic_common_match ((version), (patterns), \
|
||||
@ -144,6 +148,7 @@ typedef struct oceanic_common_layout_t {
|
||||
unsigned int rb_logbook_begin;
|
||||
unsigned int rb_logbook_end;
|
||||
unsigned int rb_logbook_entry_size;
|
||||
unsigned int rb_logbook_direction;
|
||||
// Profile ringbuffer
|
||||
unsigned int rb_profile_begin;
|
||||
unsigned int rb_profile_end;
|
||||
@ -168,7 +173,9 @@ typedef struct oceanic_common_device_t {
|
||||
|
||||
typedef struct oceanic_common_device_vtable_t {
|
||||
dc_device_vtable_t base;
|
||||
dc_status_t (*logbook) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook);
|
||||
dc_status_t (*devinfo) (dc_device_t *device, dc_event_progress_t *progress);
|
||||
dc_status_t (*pointers) (dc_device_t *device, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end);
|
||||
dc_status_t (*logbook) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end);
|
||||
dc_status_t (*profile) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata);
|
||||
} oceanic_common_device_vtable_t;
|
||||
|
||||
@ -186,7 +193,15 @@ void
|
||||
oceanic_common_device_init (oceanic_common_device_t *device);
|
||||
|
||||
dc_status_t
|
||||
oceanic_common_device_logbook (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook);
|
||||
oceanic_common_device_devinfo (dc_device_t *device, dc_event_progress_t *progress);
|
||||
|
||||
dc_status_t
|
||||
oceanic_common_device_pointers (dc_device_t *device, dc_event_progress_t *progress,
|
||||
unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end,
|
||||
unsigned int *rb_profile_begin, unsigned int *rb_profile_end);
|
||||
|
||||
dc_status_t
|
||||
oceanic_common_device_logbook (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end);
|
||||
|
||||
dc_status_t
|
||||
oceanic_common_device_profile (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata);
|
||||
|
||||
@ -58,6 +58,8 @@ static const oceanic_common_device_vtable_t oceanic_veo250_device_vtable = {
|
||||
NULL, /* timesync */
|
||||
oceanic_veo250_device_close /* close */
|
||||
},
|
||||
oceanic_common_device_devinfo,
|
||||
oceanic_common_device_pointers,
|
||||
oceanic_common_device_logbook,
|
||||
oceanic_common_device_profile,
|
||||
};
|
||||
@ -70,6 +72,7 @@ static const oceanic_common_layout_t oceanic_veo250_layout = {
|
||||
0x0400, /* rb_logbook_begin */
|
||||
0x0600, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0600, /* rb_profile_begin */
|
||||
0x8000, /* rb_profile_end */
|
||||
1, /* pt_mode_global */
|
||||
|
||||
@ -37,7 +37,7 @@ dc_status_t
|
||||
oceanic_veo250_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
oceanic_veo250_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
oceanic_veo250_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -42,7 +42,6 @@ struct oceanic_veo250_parser_t {
|
||||
double maxdepth;
|
||||
};
|
||||
|
||||
static dc_status_t oceanic_veo250_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t oceanic_veo250_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t oceanic_veo250_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -50,7 +49,6 @@ static dc_status_t oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract,
|
||||
static const dc_parser_vtable_t oceanic_veo250_parser_vtable = {
|
||||
sizeof(oceanic_veo250_parser_t),
|
||||
DC_FAMILY_OCEANIC_VEO250,
|
||||
oceanic_veo250_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -62,7 +60,7 @@ static const dc_parser_vtable_t oceanic_veo250_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
oceanic_veo250_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
oceanic_veo250_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
{
|
||||
oceanic_veo250_parser_t *parser = NULL;
|
||||
|
||||
@ -70,7 +68,7 @@ oceanic_veo250_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (oceanic_veo250_parser_t *) dc_parser_allocate (context, &oceanic_veo250_parser_vtable);
|
||||
parser = (oceanic_veo250_parser_t *) dc_parser_allocate (context, &oceanic_veo250_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -88,20 +86,6 @@ oceanic_veo250_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
oceanic_veo250_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
oceanic_veo250_parser_t *parser = (oceanic_veo250_parser_t *) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 0;
|
||||
parser->divetime = 0;
|
||||
parser->maxdepth = 0.0;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
oceanic_veo250_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -170,6 +154,7 @@ oceanic_veo250_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
|
||||
*((unsigned int *) value) = 1;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.0;
|
||||
if (data[footer + 6])
|
||||
gasmix->oxygen = data[footer + 6] / 100.0;
|
||||
@ -230,19 +215,19 @@ oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
|
||||
// Time.
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Vendor specific data
|
||||
sample.vendor.type = SAMPLE_VENDOR_OCEANIC_VEO250;
|
||||
sample.vendor.size = PAGESIZE / 2;
|
||||
sample.vendor.data = data + offset;
|
||||
if (callback) callback (DC_SAMPLE_VENDOR, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_VENDOR, &sample, userdata);
|
||||
|
||||
// Depth (ft)
|
||||
unsigned int depth = data[offset + 2];
|
||||
sample.depth = depth * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Temperature (°F)
|
||||
unsigned int temperature;
|
||||
@ -253,7 +238,7 @@ oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
temperature = data[offset + 7];
|
||||
}
|
||||
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);
|
||||
|
||||
// NDL / Deco
|
||||
unsigned int have_deco = 0;
|
||||
@ -277,7 +262,8 @@ oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
sample.deco.depth = 0.0;
|
||||
}
|
||||
sample.deco.time = decotime * 60;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
}
|
||||
|
||||
offset += PAGESIZE / 2;
|
||||
|
||||
@ -51,7 +51,8 @@ typedef struct oceanic_vtpro_device_t {
|
||||
oceanic_vtpro_protocol_t protocol;
|
||||
} oceanic_vtpro_device_t;
|
||||
|
||||
static dc_status_t oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook);
|
||||
static dc_status_t oceanic_vtpro_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end);
|
||||
static dc_status_t oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end);
|
||||
static dc_status_t oceanic_vtpro_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size);
|
||||
static dc_status_t oceanic_vtpro_device_close (dc_device_t *abstract);
|
||||
|
||||
@ -67,6 +68,8 @@ static const oceanic_common_device_vtable_t oceanic_vtpro_device_vtable = {
|
||||
NULL, /* timesync */
|
||||
oceanic_vtpro_device_close /* close */
|
||||
},
|
||||
oceanic_common_device_devinfo,
|
||||
oceanic_vtpro_device_pointers,
|
||||
oceanic_vtpro_device_logbook,
|
||||
oceanic_common_device_profile,
|
||||
};
|
||||
@ -79,6 +82,7 @@ static const oceanic_common_layout_t oceanic_vtpro_layout = {
|
||||
0x0240, /* rb_logbook_begin */
|
||||
0x0440, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x0440, /* rb_profile_begin */
|
||||
0x8000, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -94,6 +98,7 @@ static const oceanic_common_layout_t oceanic_wisdom_layout = {
|
||||
0x03D0, /* rb_logbook_begin */
|
||||
0x05D0, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x05D0, /* rb_profile_begin */
|
||||
0x8000, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -109,6 +114,7 @@ static const oceanic_common_layout_t aeris_500ai_layout = {
|
||||
0x0200, /* rb_logbook_begin */
|
||||
0x0200, /* rb_logbook_end */
|
||||
8, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x00200, /* rb_profile_begin */
|
||||
0x20000, /* rb_profile_end */
|
||||
0, /* pt_mode_global */
|
||||
@ -286,7 +292,49 @@ oceanic_vtpro_calibrate (oceanic_vtpro_device_t *device)
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook)
|
||||
oceanic_aeris500ai_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract;
|
||||
|
||||
assert (device != NULL);
|
||||
assert (device->base.layout != NULL);
|
||||
assert (rb_logbook_begin != NULL && rb_logbook_end != NULL);
|
||||
assert (rb_profile_begin != NULL && rb_profile_end != NULL);
|
||||
|
||||
const oceanic_common_layout_t *layout = device->base.layout;
|
||||
|
||||
// Read the pointer data.
|
||||
unsigned char pointers[PAGESIZE] = {0};
|
||||
status = oceanic_vtpro_device_read (abstract, layout->cf_pointers, pointers, sizeof (pointers));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the memory page.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Update and emit a progress event.
|
||||
if (progress) {
|
||||
progress->current += PAGESIZE;
|
||||
progress->maximum += PAGESIZE;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
|
||||
}
|
||||
|
||||
// Get the pointers.
|
||||
unsigned int rb_logbook_first = pointers[0x02];
|
||||
unsigned int rb_logbook_last = pointers[0x03];
|
||||
unsigned int rb_profile_first = array_uint16_le (pointers + 4) * PAGESIZE;
|
||||
unsigned int rb_profile_last = array_uint16_le (pointers + 6) * PAGESIZE;
|
||||
|
||||
*rb_logbook_begin = rb_logbook_first;
|
||||
*rb_logbook_end = rb_logbook_last;
|
||||
*rb_profile_begin = rb_profile_first;
|
||||
*rb_profile_end = rb_profile_last;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract;
|
||||
@ -297,36 +345,25 @@ oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *p
|
||||
assert (device->base.layout->rb_logbook_begin == device->base.layout->rb_logbook_end);
|
||||
assert (progress != NULL);
|
||||
|
||||
const oceanic_common_layout_t *layout = device->base.layout;
|
||||
|
||||
// Erase the buffer.
|
||||
if (!dc_buffer_clear (logbook))
|
||||
return DC_STATUS_NOMEMORY;
|
||||
|
||||
// Read the pointer data.
|
||||
unsigned char pointers[PAGESIZE] = {0};
|
||||
rc = oceanic_vtpro_device_read (abstract, layout->cf_pointers, pointers, sizeof (pointers));
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to read the memory page.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Get the logbook pointers.
|
||||
unsigned int last = pointers[0x03];
|
||||
// Get the number of dives.
|
||||
unsigned int ndives = end - begin + 1;
|
||||
|
||||
// Update and emit a progress event.
|
||||
progress->current += PAGESIZE;
|
||||
progress->maximum += PAGESIZE + (last + 1) * PAGESIZE / 2;
|
||||
progress->maximum += ndives * PAGESIZE / 2;
|
||||
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
|
||||
|
||||
// Allocate memory for the logbook entries.
|
||||
if (!dc_buffer_reserve (logbook, (last + 1) * PAGESIZE / 2))
|
||||
if (!dc_buffer_reserve (logbook, ndives * PAGESIZE / 2))
|
||||
return DC_STATUS_NOMEMORY;
|
||||
|
||||
// Send the logbook index command.
|
||||
unsigned char command[] = {0x52,
|
||||
(last >> 8) & 0xFF, // high
|
||||
(last ) & 0xFF, // low
|
||||
begin & 0xFF,
|
||||
end & 0xFF,
|
||||
0x00};
|
||||
rc = oceanic_vtpro_transfer (device, command, sizeof (command), NULL, 0);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
@ -335,7 +372,7 @@ oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *p
|
||||
}
|
||||
|
||||
// Read the logbook index.
|
||||
for (unsigned int i = 0; i < last + 1; ++i) {
|
||||
for (unsigned int i = 0; i < ndives; ++i) {
|
||||
// Receive the answer of the dive computer.
|
||||
unsigned char answer[PAGESIZE / 2 + 1] = {0};
|
||||
rc = dc_iostream_read (device->iostream, answer, sizeof(answer), NULL);
|
||||
@ -374,14 +411,26 @@ oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *p
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook)
|
||||
oceanic_vtpro_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end)
|
||||
{
|
||||
oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract;
|
||||
|
||||
if (device->base.model == AERIS500AI) {
|
||||
return oceanic_aeris500ai_device_logbook (abstract, progress, logbook);
|
||||
return oceanic_aeris500ai_device_pointers (abstract, progress, rb_logbook_begin, rb_logbook_end, rb_profile_begin, rb_profile_end);
|
||||
} else {
|
||||
return oceanic_common_device_logbook (abstract, progress, logbook);
|
||||
return oceanic_common_device_pointers (abstract, progress, rb_logbook_begin, rb_logbook_end, rb_profile_begin, rb_profile_end);
|
||||
}
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end)
|
||||
{
|
||||
oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract;
|
||||
|
||||
if (device->base.model == AERIS500AI) {
|
||||
return oceanic_aeris500ai_device_logbook (abstract, progress, logbook, begin, end);
|
||||
} else {
|
||||
return oceanic_common_device_logbook (abstract, progress, logbook, begin, end);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -37,7 +37,7 @@ dc_status_t
|
||||
oceanic_vtpro_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
|
||||
|
||||
dc_status_t
|
||||
oceanic_vtpro_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
|
||||
oceanic_vtpro_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -42,7 +42,6 @@ struct oceanic_vtpro_parser_t {
|
||||
double maxdepth;
|
||||
};
|
||||
|
||||
static dc_status_t oceanic_vtpro_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t oceanic_vtpro_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t oceanic_vtpro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -50,7 +49,6 @@ static dc_status_t oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract,
|
||||
static const dc_parser_vtable_t oceanic_vtpro_parser_vtable = {
|
||||
sizeof(oceanic_vtpro_parser_t),
|
||||
DC_FAMILY_OCEANIC_VTPRO,
|
||||
oceanic_vtpro_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -62,7 +60,7 @@ static const dc_parser_vtable_t oceanic_vtpro_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
oceanic_vtpro_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
|
||||
oceanic_vtpro_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model)
|
||||
{
|
||||
oceanic_vtpro_parser_t *parser = NULL;
|
||||
|
||||
@ -70,7 +68,7 @@ oceanic_vtpro_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (oceanic_vtpro_parser_t *) dc_parser_allocate (context, &oceanic_vtpro_parser_vtable);
|
||||
parser = (oceanic_vtpro_parser_t *) dc_parser_allocate (context, &oceanic_vtpro_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -88,20 +86,6 @@ oceanic_vtpro_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
oceanic_vtpro_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
oceanic_vtpro_parser_t *parser = (oceanic_vtpro_parser_t *) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 0;
|
||||
parser->divetime = 0;
|
||||
parser->maxdepth = 0.0;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
oceanic_vtpro_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -200,6 +184,7 @@ oceanic_vtpro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
|
||||
*((unsigned int *) value) = 1;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.0;
|
||||
if (oxygen)
|
||||
gasmix->oxygen = oxygen / 100.0;
|
||||
@ -220,6 +205,7 @@ oceanic_vtpro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
|
||||
tank->gasmix = flags;
|
||||
tank->beginpressure = beginpressure * 2 * PSI / BAR;
|
||||
tank->endpressure = endpressure * 2 * PSI / BAR;
|
||||
tank->usage = DC_USAGE_NONE;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
@ -331,14 +317,14 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
time = timestamp * 60 + (i + 1) * interval;
|
||||
else
|
||||
time = timestamp * 60 + (i + 1) * 60.0 / count + 0.5;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Vendor specific data
|
||||
sample.vendor.type = SAMPLE_VENDOR_OCEANIC_VTPRO;
|
||||
sample.vendor.size = PAGESIZE / 2;
|
||||
sample.vendor.data = data + offset;
|
||||
if (callback) callback (DC_SAMPLE_VENDOR, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_VENDOR, &sample, userdata);
|
||||
|
||||
// Depth (ft)
|
||||
unsigned int depth = 0;
|
||||
@ -348,7 +334,7 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
depth = data[offset + 3];
|
||||
}
|
||||
sample.depth = depth * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Temperature (°F)
|
||||
unsigned int temperature = 0;
|
||||
@ -358,7 +344,7 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
temperature = data[offset + 6];
|
||||
}
|
||||
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);
|
||||
|
||||
// NDL / Deco
|
||||
if (parser->model != AERIS500AI) {
|
||||
@ -372,7 +358,8 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
sample.deco.depth = 0.0;
|
||||
}
|
||||
sample.deco.time = decotime * 60;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
}
|
||||
|
||||
offset += PAGESIZE / 2;
|
||||
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
oceans_s1_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
oceans_s1_parser_create (dc_parser_t **parser, dc_context_t *context);
|
||||
oceans_s1_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -58,7 +58,6 @@ struct oceans_s1_parser_t {
|
||||
unsigned int divetime;
|
||||
};
|
||||
|
||||
static dc_status_t oceans_s1_parser_set_data(dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t oceans_s1_parser_get_datetime(dc_parser_t *abstract, dc_datetime_t *datetime);
|
||||
static dc_status_t oceans_s1_parser_get_field(dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
|
||||
static dc_status_t oceans_s1_parser_samples_foreach(dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
|
||||
@ -66,7 +65,6 @@ static dc_status_t oceans_s1_parser_samples_foreach(dc_parser_t *abstract, dc_sa
|
||||
static const dc_parser_vtable_t oceans_s1_parser_vtable = {
|
||||
sizeof(oceans_s1_parser_t),
|
||||
DC_FAMILY_OCEANS_S1,
|
||||
oceans_s1_parser_set_data, /* set_data */
|
||||
NULL, /* set_clock */
|
||||
NULL, /* set_atmospheric */
|
||||
NULL, /* set_density */
|
||||
@ -77,7 +75,7 @@ static const dc_parser_vtable_t oceans_s1_parser_vtable = {
|
||||
};
|
||||
|
||||
dc_status_t
|
||||
oceans_s1_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
oceans_s1_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
oceans_s1_parser_t *parser = NULL;
|
||||
|
||||
@ -85,7 +83,7 @@ oceans_s1_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (oceans_s1_parser_t *) dc_parser_allocate (context, &oceans_s1_parser_vtable);
|
||||
parser = (oceans_s1_parser_t *) dc_parser_allocate (context, &oceans_s1_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -105,23 +103,6 @@ oceans_s1_parser_create (dc_parser_t **out, dc_context_t *context)
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
oceans_s1_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
oceans_s1_parser_t *parser = (oceans_s1_parser_t *) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 0;
|
||||
parser->timestamp = 0;
|
||||
parser->number = 0;
|
||||
parser->divemode = 0;
|
||||
parser->oxygen = 0;
|
||||
parser->maxdepth = 0;
|
||||
parser->divetime = 0;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
oceans_s1_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -166,6 +147,7 @@ oceans_s1_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigne
|
||||
*((unsigned int *) value) = parser->divemode == SCUBA;
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
gasmix->usage = DC_USAGE_NONE;
|
||||
gasmix->helium = 0.0;
|
||||
gasmix->oxygen = parser->oxygen / 100.0;
|
||||
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
|
||||
@ -249,19 +231,19 @@ oceans_s1_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca
|
||||
unsigned int nsamples = seconds / interval;
|
||||
for (unsigned int i = 0; i < nsamples; ++i) {
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
sample.depth = 0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
}
|
||||
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
sample.depth = depth / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
} else if (strncmp(line, "enddive", 7) == 0) {
|
||||
if (sscanf(line, "enddive %u,%u", &maxdepth, &divetime) != 2) {
|
||||
ERROR (parser->base.context, "Failed to parse the line '%s'.", line);
|
||||
@ -280,14 +262,14 @@ oceans_s1_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca
|
||||
}
|
||||
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
sample.depth = depth / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
sample.temperature = temperature;
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
|
||||
if (events & EVENT_DECO_STOP) {
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
@ -298,7 +280,8 @@ oceans_s1_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca
|
||||
}
|
||||
sample.deco.depth = 0.0;
|
||||
sample.deco.time = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
|
||||
sample.deco.tts = 0;
|
||||
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -41,7 +41,7 @@ typedef struct dc_parser_vtable_t dc_parser_vtable_t;
|
||||
struct dc_parser_t {
|
||||
const dc_parser_vtable_t *vtable;
|
||||
dc_context_t *context;
|
||||
const unsigned char *data;
|
||||
unsigned char *data;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
@ -50,8 +50,6 @@ struct dc_parser_vtable_t {
|
||||
|
||||
dc_family_t type;
|
||||
|
||||
dc_status_t (*set_data) (dc_parser_t *parser, const unsigned char *data, unsigned int size);
|
||||
|
||||
dc_status_t (*set_clock) (dc_parser_t *parser, unsigned int devtime, dc_ticks_t systime);
|
||||
|
||||
dc_status_t (*set_atmospheric) (dc_parser_t *parser, double atmospheric);
|
||||
@ -68,7 +66,7 @@ struct dc_parser_vtable_t {
|
||||
};
|
||||
|
||||
dc_parser_t *
|
||||
dc_parser_allocate (dc_context_t *context, const dc_parser_vtable_t *vtable);
|
||||
dc_parser_allocate (dc_context_t *context, const dc_parser_vtable_t *vtable, const unsigned char data[], size_t size);
|
||||
|
||||
void
|
||||
dc_parser_deallocate (dc_parser_t *parser);
|
||||
@ -84,7 +82,7 @@ typedef struct sample_statistics_t {
|
||||
#define SAMPLE_STATISTICS_INITIALIZER {0, 0.0}
|
||||
|
||||
void
|
||||
sample_statistics_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata);
|
||||
sample_statistics_cb (dc_sample_type_t type, const dc_sample_value_t *value, void *userdata);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
163
src/parser.c
163
src/parser.c
@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "suunto_d9.h"
|
||||
@ -72,7 +73,7 @@
|
||||
#define REACTPROWHITE 0x4354
|
||||
|
||||
static dc_status_t
|
||||
dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t family, unsigned int model, unsigned int devtime, dc_ticks_t systime)
|
||||
dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, dc_family_t family, unsigned int model)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
dc_parser_t *parser = NULL;
|
||||
@ -82,126 +83,127 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t fa
|
||||
|
||||
switch (family) {
|
||||
case DC_FAMILY_SUUNTO_SOLUTION:
|
||||
rc = suunto_solution_parser_create (&parser, context);
|
||||
rc = suunto_solution_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_SUUNTO_EON:
|
||||
rc = suunto_eon_parser_create (&parser, context, 0);
|
||||
rc = suunto_eon_parser_create (&parser, context, data, size, 0);
|
||||
break;
|
||||
case DC_FAMILY_SUUNTO_VYPER:
|
||||
if (model == 0x01)
|
||||
rc = suunto_eon_parser_create (&parser, context, 1);
|
||||
rc = suunto_eon_parser_create (&parser, context, data, size, 1);
|
||||
else
|
||||
rc = suunto_vyper_parser_create (&parser, context);
|
||||
rc = suunto_vyper_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_SUUNTO_VYPER2:
|
||||
case DC_FAMILY_SUUNTO_D9:
|
||||
rc = suunto_d9_parser_create (&parser, context, model);
|
||||
rc = suunto_d9_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_SUUNTO_EONSTEEL:
|
||||
rc = suunto_eonsteel_parser_create(&parser, context, model);
|
||||
rc = suunto_eonsteel_parser_create(&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_UWATEC_ALADIN:
|
||||
case DC_FAMILY_UWATEC_MEMOMOUSE:
|
||||
rc = uwatec_memomouse_parser_create (&parser, context, devtime, systime);
|
||||
rc = uwatec_memomouse_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_UWATEC_SMART:
|
||||
rc = uwatec_smart_parser_create (&parser, context, model);
|
||||
rc = uwatec_smart_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_REEFNET_SENSUS:
|
||||
rc = reefnet_sensus_parser_create (&parser, context, devtime, systime);
|
||||
rc = reefnet_sensus_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_REEFNET_SENSUSPRO:
|
||||
rc = reefnet_sensuspro_parser_create (&parser, context, devtime, systime);
|
||||
rc = reefnet_sensuspro_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_REEFNET_SENSUSULTRA:
|
||||
rc = reefnet_sensusultra_parser_create (&parser, context, devtime, systime);
|
||||
rc = reefnet_sensusultra_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_OCEANIC_VTPRO:
|
||||
rc = oceanic_vtpro_parser_create (&parser, context, model);
|
||||
rc = oceanic_vtpro_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_OCEANIC_VEO250:
|
||||
rc = oceanic_veo250_parser_create (&parser, context, model);
|
||||
rc = oceanic_veo250_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_OCEANIC_ATOM2:
|
||||
case DC_FAMILY_PELAGIC_I330R:
|
||||
if (model == REACTPROWHITE)
|
||||
rc = oceanic_veo250_parser_create (&parser, context, model);
|
||||
rc = oceanic_veo250_parser_create (&parser, context, data, size, model);
|
||||
else
|
||||
rc = oceanic_atom2_parser_create (&parser, context, model);
|
||||
rc = oceanic_atom2_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_MARES_NEMO:
|
||||
case DC_FAMILY_MARES_PUCK:
|
||||
rc = mares_nemo_parser_create (&parser, context, model);
|
||||
rc = mares_nemo_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_MARES_DARWIN:
|
||||
rc = mares_darwin_parser_create (&parser, context, model);
|
||||
rc = mares_darwin_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_MARES_ICONHD:
|
||||
rc = mares_iconhd_parser_create (&parser, context, model);
|
||||
rc = mares_iconhd_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_HW_OSTC:
|
||||
rc = hw_ostc_parser_create (&parser, context);
|
||||
rc = hw_ostc_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_HW_FROG:
|
||||
case DC_FAMILY_HW_OSTC3:
|
||||
rc = hw_ostc3_parser_create (&parser, context, model);
|
||||
rc = hw_ostc3_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_CRESSI_EDY:
|
||||
case DC_FAMILY_ZEAGLE_N2ITION3:
|
||||
rc = cressi_edy_parser_create (&parser, context, model);
|
||||
rc = cressi_edy_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_CRESSI_LEONARDO:
|
||||
rc = cressi_leonardo_parser_create (&parser, context, model);
|
||||
rc = cressi_leonardo_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_CRESSI_GOA:
|
||||
rc = cressi_goa_parser_create (&parser, context, model);
|
||||
rc = cressi_goa_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_ATOMICS_COBALT:
|
||||
rc = atomics_cobalt_parser_create (&parser, context);
|
||||
rc = atomics_cobalt_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_SHEARWATER_PREDATOR:
|
||||
rc = shearwater_predator_parser_create (&parser, context, model);
|
||||
rc = shearwater_predator_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_SHEARWATER_PETREL:
|
||||
rc = shearwater_petrel_parser_create (&parser, context, model);
|
||||
rc = shearwater_petrel_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_DIVERITE_NITEKQ:
|
||||
rc = diverite_nitekq_parser_create (&parser, context);
|
||||
rc = diverite_nitekq_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_CITIZEN_AQUALAND:
|
||||
rc = citizen_aqualand_parser_create (&parser, context);
|
||||
rc = citizen_aqualand_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_DIVESYSTEM_IDIVE:
|
||||
rc = divesystem_idive_parser_create (&parser, context, model);
|
||||
rc = divesystem_idive_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_COCHRAN_COMMANDER:
|
||||
rc = cochran_commander_parser_create (&parser, context, model);
|
||||
rc = cochran_commander_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_TECDIVING_DIVECOMPUTEREU:
|
||||
rc = tecdiving_divecomputereu_parser_create (&parser, context);
|
||||
rc = tecdiving_divecomputereu_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_MCLEAN_EXTREME:
|
||||
rc = mclean_extreme_parser_create (&parser, context);
|
||||
rc = mclean_extreme_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_LIQUIVISION_LYNX:
|
||||
rc = liquivision_lynx_parser_create (&parser, context, model);
|
||||
rc = liquivision_lynx_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_SPORASUB_SP2:
|
||||
rc = sporasub_sp2_parser_create (&parser, context);
|
||||
rc = sporasub_sp2_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_DEEPSIX_EXCURSION:
|
||||
rc = deepsix_excursion_parser_create (&parser, context);
|
||||
rc = deepsix_excursion_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_SEAC_SCREEN:
|
||||
rc = seac_screen_parser_create (&parser, context);
|
||||
rc = seac_screen_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_DEEPBLU_COSMIQ:
|
||||
rc = deepblu_cosmiq_parser_create (&parser, context);
|
||||
rc = deepblu_cosmiq_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_OCEANS_S1:
|
||||
rc = oceans_s1_parser_create (&parser, context);
|
||||
rc = oceans_s1_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
case DC_FAMILY_DIVESOFT_FREEDOM:
|
||||
rc = divesoft_freedom_parser_create (&parser, context);
|
||||
rc = divesoft_freedom_parser_create (&parser, context, data, size);
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
@ -213,26 +215,42 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t fa
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_parser_new (dc_parser_t **out, dc_device_t *device)
|
||||
dc_parser_new (dc_parser_t **out, dc_device_t *device, const unsigned char data[], size_t size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_parser_t *parser = NULL;
|
||||
|
||||
if (device == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
return dc_parser_new_internal (out, device->context,
|
||||
dc_device_get_type (device), device->devinfo.model,
|
||||
device->clock.devtime, device->clock.systime);
|
||||
status = dc_parser_new_internal (&parser, device->context, data, size,
|
||||
dc_device_get_type (device), device->devinfo.model);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
goto error_exit;
|
||||
|
||||
status = dc_parser_set_clock (parser, device->clock.devtime, device->clock.systime);
|
||||
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED)
|
||||
goto error_free;
|
||||
|
||||
*out = parser;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free:
|
||||
dc_parser_deallocate (parser);
|
||||
error_exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_parser_new2 (dc_parser_t **out, dc_context_t *context, dc_descriptor_t *descriptor, unsigned int devtime, dc_ticks_t systime)
|
||||
dc_parser_new2 (dc_parser_t **out, dc_context_t *context, dc_descriptor_t *descriptor, const unsigned char data[], size_t size)
|
||||
{
|
||||
return dc_parser_new_internal (out, context,
|
||||
dc_descriptor_get_type (descriptor), dc_descriptor_get_model (descriptor),
|
||||
devtime, systime);
|
||||
return dc_parser_new_internal (out, context, data, size,
|
||||
dc_descriptor_get_type (descriptor), dc_descriptor_get_model (descriptor));
|
||||
}
|
||||
|
||||
dc_parser_t *
|
||||
dc_parser_allocate (dc_context_t *context, const dc_parser_vtable_t *vtable)
|
||||
dc_parser_allocate (dc_context_t *context, const dc_parser_vtable_t *vtable, const unsigned char data[], size_t size)
|
||||
{
|
||||
dc_parser_t *parser = NULL;
|
||||
|
||||
@ -249,15 +267,34 @@ dc_parser_allocate (dc_context_t *context, const dc_parser_vtable_t *vtable)
|
||||
// Initialize the base class.
|
||||
parser->vtable = vtable;
|
||||
parser->context = context;
|
||||
parser->data = NULL;
|
||||
parser->size = 0;
|
||||
|
||||
if (size) {
|
||||
// Allocate memory for the data.
|
||||
parser->data = malloc (size);
|
||||
if (parser->data == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
free (parser);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Copy the data.
|
||||
memcpy (parser->data, data, size);
|
||||
parser->size = size;
|
||||
} else {
|
||||
parser->data = NULL;
|
||||
parser->size = 0;
|
||||
|
||||
}
|
||||
return parser;
|
||||
}
|
||||
|
||||
void
|
||||
dc_parser_deallocate (dc_parser_t *parser)
|
||||
{
|
||||
if (parser == NULL)
|
||||
return;
|
||||
|
||||
free (parser->data);
|
||||
free (parser);
|
||||
}
|
||||
|
||||
@ -320,22 +357,6 @@ dc_parser_set_density (dc_parser_t *parser, double density)
|
||||
}
|
||||
|
||||
|
||||
dc_status_t
|
||||
dc_parser_set_data (dc_parser_t *parser, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
if (parser == NULL)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
|
||||
if (parser->vtable->set_data == NULL)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
|
||||
parser->data = data;
|
||||
parser->size = size;
|
||||
|
||||
return parser->vtable->set_data (parser, data, size);
|
||||
}
|
||||
|
||||
|
||||
dc_status_t
|
||||
dc_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime)
|
||||
{
|
||||
@ -393,17 +414,17 @@ dc_parser_destroy (dc_parser_t *parser)
|
||||
|
||||
|
||||
void
|
||||
sample_statistics_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata)
|
||||
sample_statistics_cb (dc_sample_type_t type, const dc_sample_value_t *value, void *userdata)
|
||||
{
|
||||
sample_statistics_t *statistics = (sample_statistics_t *) userdata;
|
||||
|
||||
switch (type) {
|
||||
case DC_SAMPLE_TIME:
|
||||
statistics->divetime = value.time;
|
||||
statistics->divetime = value->time / 1000;
|
||||
break;
|
||||
case DC_SAMPLE_DEPTH:
|
||||
if (statistics->maxdepth < value.depth)
|
||||
statistics->maxdepth = value.depth;
|
||||
if (statistics->maxdepth < value->depth)
|
||||
statistics->maxdepth = value->depth;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
646
src/pelagic_i330r.c
Normal file
646
src/pelagic_i330r.c
Normal file
@ -0,0 +1,646 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2023 Janice McLaughlin
|
||||
*
|
||||
* 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> // memcpy
|
||||
#include <stdlib.h> // malloc, free
|
||||
#include <assert.h>
|
||||
|
||||
#include <libdivecomputer/ble.h>
|
||||
|
||||
#include "pelagic_i330r.h"
|
||||
#include "oceanic_common.h"
|
||||
|
||||
#include "context-private.h"
|
||||
#include "device-private.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "rbstream.h"
|
||||
#include "checksum.h"
|
||||
#include "array.h"
|
||||
|
||||
#define UNDEFINED 0
|
||||
|
||||
#define STARTBYTE 0xCD
|
||||
|
||||
#define FLAG_NONE 0x00
|
||||
#define FLAG_REQUEST 0x40
|
||||
#define FLAG_DATA 0x80
|
||||
#define FLAG_LAST 0xC0
|
||||
|
||||
#define CMD_ACCESS_REQUEST 0xFA
|
||||
#define CMD_ACCESS_CODE 0xFB
|
||||
#define CMD_AUTHENTICATION 0x97
|
||||
#define CMD_WAKEUP_RDONLY 0x21
|
||||
#define CMD_WAKEUP_RDWR 0x22
|
||||
#define CMD_READ_HW_CAL 0x27
|
||||
#define CMD_READ_A2D 0x25
|
||||
#define CMD_READ_DEVICE_REC 0x31
|
||||
#define CMD_READ_GEN_SET 0x29
|
||||
#define CMD_READ_EXFLASHMAP 0x2F
|
||||
#define CMD_READ_FLASH 0x0D
|
||||
|
||||
#define RSP_READY 1
|
||||
#define RSP_DONE 2
|
||||
|
||||
#define MAXPACKET 255
|
||||
|
||||
#define MAXPASSCODE 6
|
||||
|
||||
typedef struct pelagic_i330r_device_t {
|
||||
oceanic_common_device_t base;
|
||||
dc_iostream_t *iostream;
|
||||
unsigned char accesscode[16];
|
||||
unsigned char id[16];
|
||||
unsigned char hwcal[256];
|
||||
unsigned char flashmap[256];
|
||||
unsigned int model;
|
||||
} pelagic_i330r_device_t;
|
||||
|
||||
static dc_status_t pelagic_i330r_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size);
|
||||
static dc_status_t pelagic_i330r_device_devinfo (dc_device_t *abstract, dc_event_progress_t *progress);
|
||||
static dc_status_t pelagic_i330r_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end);
|
||||
|
||||
static const oceanic_common_device_vtable_t pelagic_i330r_device_vtable = {
|
||||
{
|
||||
sizeof(pelagic_i330r_device_t),
|
||||
DC_FAMILY_PELAGIC_I330R,
|
||||
oceanic_common_device_set_fingerprint, /* set_fingerprint */
|
||||
pelagic_i330r_device_read, /* read */
|
||||
NULL, /* write */
|
||||
oceanic_common_device_dump, /* dump */
|
||||
oceanic_common_device_foreach, /* foreach */
|
||||
NULL, /* timesync */
|
||||
NULL /* close */
|
||||
},
|
||||
pelagic_i330r_device_devinfo,
|
||||
pelagic_i330r_device_pointers,
|
||||
oceanic_common_device_logbook,
|
||||
oceanic_common_device_profile,
|
||||
};
|
||||
|
||||
static const oceanic_common_layout_t pelagic_i330r = {
|
||||
0x00400000, /* memsize */
|
||||
0, /* highmem */
|
||||
UNDEFINED, /* cf_devinfo */
|
||||
UNDEFINED, /* cf_pointers */
|
||||
0x00102000, /* rb_logbook_begin */
|
||||
0x00106000, /* rb_logbook_end */
|
||||
64, /* rb_logbook_entry_size */
|
||||
0, /* rb_logbook_direction */
|
||||
0x0010A000, /* rb_profile_begin */
|
||||
0x00400000, /* rb_profile_end */
|
||||
1, /* pt_mode_global */
|
||||
4, /* pt_mode_logbook */
|
||||
UNDEFINED, /* pt_mode_serial */
|
||||
};
|
||||
|
||||
static const oceanic_common_layout_t pelagic_dsx = {
|
||||
0x02000000, /* memsize */
|
||||
0, /* highmem */
|
||||
UNDEFINED, /* cf_devinfo */
|
||||
UNDEFINED, /* cf_pointers */
|
||||
0x00800000, /* rb_logbook_begin */
|
||||
0x00880000, /* rb_logbook_end */
|
||||
512, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x01000000, /* rb_profile_begin */
|
||||
0x02000000, /* rb_profile_end */
|
||||
1, /* pt_mode_global */
|
||||
4, /* pt_mode_logbook */
|
||||
UNDEFINED /* pt_mode_serial */
|
||||
};
|
||||
|
||||
static unsigned char
|
||||
checksum (const unsigned char data[], unsigned int size)
|
||||
{
|
||||
unsigned int csum = 0;
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
unsigned int a = csum ^ data[i];
|
||||
unsigned int b = (a >> 7) ^ ((a >> 4) ^ a);
|
||||
csum = ((b << 4) & 0xFF) ^ ((b << 1) & 0xFF);
|
||||
}
|
||||
return csum & 0xFF;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_send (pelagic_i330r_device_t *device, unsigned char cmd, unsigned char flag, const unsigned char data[], unsigned int size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
if (size > MAXPACKET) {
|
||||
ERROR (abstract->context, "Packet payload is too large (%u).", size);
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
unsigned char packet[MAXPACKET + 5] = {
|
||||
STARTBYTE,
|
||||
flag,
|
||||
cmd,
|
||||
0,
|
||||
size
|
||||
};
|
||||
if (size) {
|
||||
memcpy(packet + 5, data, size);
|
||||
}
|
||||
packet[3] = checksum (packet, size + 5);
|
||||
|
||||
// Send the data packet.
|
||||
status = dc_iostream_write (device->iostream, packet, size + 5, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return status;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_recv (pelagic_i330r_device_t *device, unsigned char cmd, unsigned char data[], unsigned int size, unsigned int *errorcode)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
unsigned char packet[MAXPACKET + 5] = {0};
|
||||
unsigned int errcode = 0;
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
while (1) {
|
||||
// Read the data packet.
|
||||
size_t transferred = 0;
|
||||
status = dc_iostream_read (device->iostream, packet, sizeof(packet), &transferred);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the data packet.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Verify the minimum packet size.
|
||||
if (transferred < 5) {
|
||||
ERROR (abstract->context, "Invalid packet length (" DC_PRINTF_SIZE ").", transferred);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Verify the start byte.
|
||||
if (packet[0] != STARTBYTE) {
|
||||
ERROR (abstract->context, "Unexpected packet start byte (%02x).", packet[0]);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Verify the command byte.
|
||||
if (packet[2] != cmd) {
|
||||
ERROR (abstract->context, "Unexpected packet command byte (%02x).", packet[2]);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Verify the length byte.
|
||||
unsigned int length = packet[4];
|
||||
if (length + 5 > transferred) {
|
||||
ERROR (abstract->context, "Invalid packet length (%u).", length);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Verify the checksum.
|
||||
unsigned char crc = packet[3]; packet[3] = 0;
|
||||
unsigned char ccrc = checksum (packet, length + 5);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected packet checksum (%02x %02x).", crc, ccrc);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Check the flag byte for the last packet.
|
||||
unsigned char flag = packet[1];
|
||||
if ((flag & FLAG_LAST) == FLAG_LAST) {
|
||||
// The last packet (typically 2 bytes) does not get appended!
|
||||
if (length) {
|
||||
errcode = packet[5];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
unsigned int n = length;
|
||||
if (nbytes + n > size) {
|
||||
n = size - nbytes;
|
||||
}
|
||||
memcpy (data + nbytes, packet + 5, n);
|
||||
}
|
||||
nbytes += length;
|
||||
}
|
||||
|
||||
// Verify the expected number of bytes.
|
||||
if (nbytes != size) {
|
||||
ERROR (abstract->context, "Unexpected number of bytes received (%u %u).", nbytes, size);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (errorcode) {
|
||||
*errorcode = errcode;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_transfer (pelagic_i330r_device_t *device, unsigned char cmd, unsigned char flag, const unsigned char data[], unsigned int size, unsigned char answer[], unsigned int asize, unsigned int response)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
unsigned int errorcode = 0;
|
||||
|
||||
status = pelagic_i330r_send (device, cmd, flag, data, size);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = pelagic_i330r_recv (device, cmd, answer, asize, &errorcode);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (errorcode != response) {
|
||||
ERROR (abstract->context, "Unexpected response code (%u)", errorcode);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_init_accesscode (pelagic_i330r_device_t *device)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
|
||||
const unsigned char zero[9] = {0};
|
||||
status = pelagic_i330r_transfer (device, CMD_ACCESS_REQUEST, FLAG_REQUEST, zero, sizeof(zero), NULL, 0, RSP_READY);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = pelagic_i330r_transfer (device, CMD_ACCESS_REQUEST, FLAG_DATA, device->accesscode, sizeof(device->accesscode), NULL, 0, RSP_DONE);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_init_passcode (pelagic_i330r_device_t *device, const char *pincode)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
unsigned char passcode[MAXPASSCODE] = {0};
|
||||
|
||||
// Check the maximum length.
|
||||
size_t len = pincode ? strlen (pincode) : 0;
|
||||
if (len > sizeof(passcode)) {
|
||||
ERROR (abstract->context, "Invalid pincode length (" DC_PRINTF_SIZE ").", len);
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
// Convert to binary number.
|
||||
unsigned int offset = sizeof(passcode) - len;
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
unsigned char c = pincode[i];
|
||||
if (c < '0' || c > '9') {
|
||||
ERROR (abstract->context, "Invalid pincode character (%c).", c);
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
passcode[offset + i] = c - '0';
|
||||
}
|
||||
|
||||
const unsigned char zero[9] = {0};
|
||||
status = pelagic_i330r_transfer (device, CMD_ACCESS_CODE, FLAG_REQUEST, zero, sizeof(zero), NULL, 0, RSP_READY);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = pelagic_i330r_transfer (device, CMD_ACCESS_CODE, FLAG_DATA, passcode, sizeof(passcode), device->accesscode, sizeof(device->accesscode), RSP_DONE);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
HEXDUMP (abstract->context, DC_LOGLEVEL_DEBUG, "Access code", device->accesscode, sizeof(device->accesscode));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_init_handshake (pelagic_i330r_device_t *device, unsigned int readwrite)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
const unsigned char cmd = readwrite ? CMD_WAKEUP_RDWR : CMD_WAKEUP_RDONLY;
|
||||
|
||||
const unsigned char args[9] = {0, 0, 0, 0, 0x0C, 0, 0, 0, 0};
|
||||
status = pelagic_i330r_transfer (device, cmd, FLAG_REQUEST, args, sizeof(args), device->id, sizeof(device->id), RSP_DONE);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
HEXDUMP (abstract->context, DC_LOGLEVEL_DEBUG, "ID", device->id, sizeof(device->id));
|
||||
|
||||
device->model = array_uint16_be (device->id + 12);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_init_auth (pelagic_i330r_device_t *device)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
|
||||
const unsigned char args[2][9] = {
|
||||
{0xFF, 0xFF, 0xFF, 0xFF}, // DSX
|
||||
{0x37, 0x30, 0x31, 0x55}, // I330R
|
||||
};
|
||||
unsigned int args_idx = device->model == DSX ? 0 : 1;
|
||||
status = pelagic_i330r_transfer (device, CMD_AUTHENTICATION, FLAG_REQUEST, args[args_idx], sizeof(args[args_idx]), NULL, 0, RSP_READY);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_init (pelagic_i330r_device_t *device)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
// Get the bluetooth access code.
|
||||
status = dc_iostream_ioctl (device->iostream, DC_IOCTL_BLE_GET_ACCESSCODE, device->accesscode, sizeof(device->accesscode));
|
||||
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
|
||||
ERROR (abstract->context, "Failed to get the access code.");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (array_isequal (device->accesscode, sizeof(device->accesscode), 0)) {
|
||||
// Request to display the PIN code.
|
||||
status = pelagic_i330r_init_accesscode (device);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to display the PIN code.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Get the bluetooth PIN code.
|
||||
char pincode[6 + 1] = {0};
|
||||
status = dc_iostream_ioctl (device->iostream, DC_IOCTL_BLE_GET_PINCODE, pincode, sizeof(pincode));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to get the PIN code.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Force a null terminated string.
|
||||
pincode[sizeof(pincode) - 1] = 0;
|
||||
|
||||
// Request the access code.
|
||||
status = pelagic_i330r_init_passcode (device, pincode);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to request the access code.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Store the bluetooth access code.
|
||||
status = dc_iostream_ioctl (device->iostream, DC_IOCTL_BLE_SET_ACCESSCODE, device->accesscode, sizeof(device->accesscode));
|
||||
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
|
||||
ERROR (abstract->context, "Failed to store the access code.");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// Request access.
|
||||
status = pelagic_i330r_init_accesscode (device);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to request access.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Send the wakeup command.
|
||||
status = pelagic_i330r_init_handshake (device, 1);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the wakeup command.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Send the authentication code.
|
||||
status = pelagic_i330r_init_auth (device);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the authentication code.");
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_download (pelagic_i330r_device_t *device, unsigned char cmd, const unsigned char data[], unsigned int size, unsigned char answer[], unsigned int asize)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
status = pelagic_i330r_transfer (device, cmd, FLAG_REQUEST, data, size, answer, asize, RSP_DONE);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
// Verify the checksum
|
||||
unsigned short crc = array_uint16_be (answer + asize - 2);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (answer, asize - 2, 0xffff, 0x0000);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected data checksum (%04x %04x).", crc, ccrc);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
pelagic_i330r_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream, unsigned int model)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
pelagic_i330r_device_t *device = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
device = (pelagic_i330r_device_t *) dc_device_allocate (context, &pelagic_i330r_device_vtable.base);
|
||||
if (device == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Initialize the base class.
|
||||
oceanic_common_device_init (&device->base);
|
||||
|
||||
// Override the base class values.
|
||||
device->base.multipage = 256;
|
||||
|
||||
// Set the default values.
|
||||
device->iostream = iostream;
|
||||
memset (device->accesscode, 0, sizeof(device->accesscode));
|
||||
memset (device->id, 0, sizeof(device->id));
|
||||
memset (device->hwcal, 0, sizeof(device->hwcal));
|
||||
memset (device->flashmap, 0, sizeof(device->flashmap));
|
||||
device->model = 0;
|
||||
|
||||
// Set the timeout for receiving data (3000 ms).
|
||||
status = dc_iostream_set_timeout (device->iostream, 3000);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the timeout.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Perform the bluetooth authentication.
|
||||
status = pelagic_i330r_init (device);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to perform the bluetooth authentication.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Download the calibration data.
|
||||
const unsigned char args[9] = {0, 0, 0, 0, 0, 0x01, 0, 0, 0};
|
||||
status = pelagic_i330r_download (device, CMD_READ_HW_CAL, args, sizeof(args), device->hwcal, sizeof(device->hwcal));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to download the calibration data.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
HEXDUMP (context, DC_LOGLEVEL_DEBUG, "Hwcal", device->hwcal, sizeof(device->hwcal));
|
||||
|
||||
// Download the flash map.
|
||||
const unsigned char zero[9] = {0};
|
||||
status = pelagic_i330r_download (device, CMD_READ_EXFLASHMAP, zero, sizeof(zero), device->flashmap, sizeof(device->flashmap));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to download the flash map.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
HEXDUMP (context, DC_LOGLEVEL_DEBUG, "Flashmap", device->flashmap, sizeof(device->flashmap));
|
||||
|
||||
// Detect the memory layout.
|
||||
if (device->model == DSX) {
|
||||
device->base.layout = &pelagic_dsx;
|
||||
} else {
|
||||
device->base.layout = &pelagic_i330r;
|
||||
}
|
||||
|
||||
*out = (dc_device_t *) device;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free:
|
||||
dc_device_deallocate ((dc_device_t *) device);
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
pelagic_i330r_device_t *device = (pelagic_i330r_device_t*) abstract;
|
||||
|
||||
unsigned char command[9] = {0};
|
||||
array_uint32_le_set(command + 0, address);
|
||||
array_uint32_le_set(command + 4, size);
|
||||
|
||||
status = pelagic_i330r_transfer (device, CMD_READ_FLASH, FLAG_NONE, command, sizeof(command), data, size, RSP_DONE);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_device_devinfo (dc_device_t *abstract, dc_event_progress_t *progress)
|
||||
{
|
||||
pelagic_i330r_device_t *device = (pelagic_i330r_device_t *) abstract;
|
||||
|
||||
assert (device != NULL);
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = device->model;
|
||||
devinfo.firmware = 0;
|
||||
devinfo.serial =
|
||||
bcd2dec (device->hwcal[12]) +
|
||||
bcd2dec (device->hwcal[13]) * 100 +
|
||||
bcd2dec (device->hwcal[14]) * 10000;
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end)
|
||||
{
|
||||
pelagic_i330r_device_t *device = (pelagic_i330r_device_t *) abstract;
|
||||
|
||||
assert (device != NULL);
|
||||
assert (device->base.layout != NULL);
|
||||
assert (rb_logbook_begin != NULL && rb_logbook_end != NULL);
|
||||
assert (rb_profile_begin != NULL && rb_profile_end != NULL);
|
||||
|
||||
const oceanic_common_layout_t *layout = device->base.layout;
|
||||
|
||||
// Get the logbook pointers.
|
||||
unsigned int rb_logbook_min = array_uint32_le (device->flashmap + 0x50);
|
||||
unsigned int rb_logbook_max = array_uint32_le (device->flashmap + 0x54);
|
||||
unsigned int rb_logbook_first = array_uint32_le (device->flashmap + 0x58);
|
||||
unsigned int rb_logbook_last = array_uint32_le (device->flashmap + 0x5C);
|
||||
if (rb_logbook_min != 0 && rb_logbook_max != 0) {
|
||||
rb_logbook_max += 1;
|
||||
}
|
||||
|
||||
// Get the profile pointers.
|
||||
unsigned int rb_profile_min = array_uint32_le (device->flashmap + 0x70);
|
||||
unsigned int rb_profile_max = array_uint32_le (device->flashmap + 0x74);
|
||||
unsigned int rb_profile_first = array_uint32_le (device->flashmap + 0x78);
|
||||
unsigned int rb_profile_last = array_uint32_le (device->flashmap + 0x7C);
|
||||
if (rb_profile_min != 0 && rb_profile_max != 0) {
|
||||
rb_profile_max += 1;
|
||||
}
|
||||
|
||||
// Check the logbook ringbuffer area.
|
||||
if (rb_logbook_min != layout->rb_logbook_begin ||
|
||||
rb_logbook_max != layout->rb_logbook_end) {
|
||||
ERROR (abstract->context, "Unexpected logbook ringbuffer area (%08x %08x)",
|
||||
rb_logbook_min, rb_logbook_max);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Check the profile ringbuffer area.
|
||||
if (rb_profile_min != layout->rb_profile_begin ||
|
||||
rb_profile_max != layout->rb_profile_end) {
|
||||
ERROR (abstract->context, "Unexpected profile ringbuffer area (%08x %08x)",
|
||||
rb_profile_min, rb_profile_max);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Get the begin/end pointers.
|
||||
if (device->model == DSX) {
|
||||
*rb_logbook_begin = rb_logbook_first;
|
||||
*rb_logbook_end = rb_logbook_last;
|
||||
} else {
|
||||
*rb_logbook_begin = rb_logbook_min;
|
||||
*rb_logbook_end = rb_logbook_last + 1;
|
||||
}
|
||||
*rb_profile_begin = rb_profile_first;
|
||||
*rb_profile_end = rb_profile_last;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2017 Jef Driesen
|
||||
* Copyright (C) 2023 Janice McLaughlin
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -19,30 +19,22 @@
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef DC_DESCRIPTOR_PRIVATE_H
|
||||
#define DC_DESCRIPTOR_PRIVATE_H
|
||||
#ifndef PELAGIC_I330R_H
|
||||
#define PELAGIC_I330R_H
|
||||
|
||||
#include <libdivecomputer/descriptor.h>
|
||||
#include <libdivecomputer/context.h>
|
||||
#include <libdivecomputer/iostream.h>
|
||||
#include <libdivecomputer/device.h>
|
||||
#include <libdivecomputer/parser.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct dc_usb_desc_t {
|
||||
unsigned short vid;
|
||||
unsigned short pid;
|
||||
} dc_usb_desc_t;
|
||||
|
||||
typedef struct dc_usb_params_t {
|
||||
unsigned int interface;
|
||||
unsigned char endpoint_in;
|
||||
unsigned char endpoint_out;
|
||||
} dc_usb_params_t;
|
||||
|
||||
int
|
||||
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata, void *params);
|
||||
dc_status_t
|
||||
pelagic_i330r_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* DC_DESCRIPTOR_PRIVATE_H */
|
||||
#endif /* PELAGIC_I330R_H */
|
||||
135
src/rbstream.c
135
src/rbstream.c
@ -28,11 +28,13 @@
|
||||
|
||||
struct dc_rbstream_t {
|
||||
dc_device_t *device;
|
||||
dc_rbstream_direction_t direction;
|
||||
unsigned int pagesize;
|
||||
unsigned int packetsize;
|
||||
unsigned int begin;
|
||||
unsigned int end;
|
||||
unsigned int address;
|
||||
unsigned int offset;
|
||||
unsigned int available;
|
||||
unsigned int skip;
|
||||
unsigned char cache[];
|
||||
@ -53,7 +55,7 @@ iceil (unsigned int x, unsigned int n)
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_rbstream_new (dc_rbstream_t **out, dc_device_t *device, unsigned int pagesize, unsigned int packetsize, unsigned int begin, unsigned int end, unsigned int address)
|
||||
dc_rbstream_new (dc_rbstream_t **out, dc_device_t *device, unsigned int pagesize, unsigned int packetsize, unsigned int begin, unsigned int end, unsigned int address, dc_rbstream_direction_t direction)
|
||||
{
|
||||
dc_rbstream_t *rbstream = NULL;
|
||||
|
||||
@ -78,6 +80,18 @@ dc_rbstream_new (dc_rbstream_t **out, dc_device_t *device, unsigned int pagesize
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
// Ringbuffer boundaries should not be reversed.
|
||||
if (begin > end) {
|
||||
ERROR (device->context, "Ringbuffer boundaries reversed!");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
// Packet size should be smaller than the ringbuffer size.
|
||||
if (packetsize > (end - begin)) {
|
||||
ERROR (device->context, "Packet size larger than the ringbuffer size!");
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
// Address should be inside the ringbuffer.
|
||||
if (address < begin || address > end) {
|
||||
ERROR (device->context, "Address outside the ringbuffer!");
|
||||
@ -92,64 +106,64 @@ dc_rbstream_new (dc_rbstream_t **out, dc_device_t *device, unsigned int pagesize
|
||||
}
|
||||
|
||||
rbstream->device = device;
|
||||
rbstream->direction = direction;
|
||||
rbstream->pagesize = pagesize;
|
||||
rbstream->packetsize = packetsize;
|
||||
rbstream->begin = begin;
|
||||
rbstream->end = end;
|
||||
rbstream->address = iceil(address, pagesize);
|
||||
if (direction == DC_RBSTREAM_FORWARD) {
|
||||
rbstream->address = ifloor(address, pagesize);
|
||||
rbstream->skip = address - rbstream->address;
|
||||
} else {
|
||||
rbstream->address = iceil(address, pagesize);
|
||||
rbstream->skip = rbstream->address - address;
|
||||
}
|
||||
rbstream->offset = 0;
|
||||
rbstream->available = 0;
|
||||
rbstream->skip = rbstream->address - address;
|
||||
|
||||
*out = rbstream;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_rbstream_read (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsigned char data[], unsigned int size)
|
||||
static dc_status_t
|
||||
dc_rbstream_read_backward (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsigned char data[], unsigned int size)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
|
||||
if (rbstream == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
unsigned int address = rbstream->address;
|
||||
unsigned int available = rbstream->available;
|
||||
unsigned int skip = rbstream->skip;
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
unsigned int offset = size;
|
||||
while (nbytes < size) {
|
||||
if (available == 0) {
|
||||
if (rbstream->available == 0) {
|
||||
// Handle the ringbuffer wrap point.
|
||||
if (address == rbstream->begin)
|
||||
address = rbstream->end;
|
||||
if (rbstream->address == rbstream->begin)
|
||||
rbstream->address = rbstream->end;
|
||||
|
||||
// Calculate the packet size.
|
||||
unsigned int len = rbstream->packetsize;
|
||||
if (rbstream->begin + len > address)
|
||||
len = address - rbstream->begin;
|
||||
|
||||
// Move to the begin of the current packet.
|
||||
address -= len;
|
||||
if (rbstream->begin + len > rbstream->address)
|
||||
len = rbstream->address - rbstream->begin;
|
||||
|
||||
// Read the packet into the cache.
|
||||
rc = dc_device_read (rbstream->device, address, rbstream->cache, rbstream->packetsize);
|
||||
rc = dc_device_read (rbstream->device, rbstream->address - len, rbstream->cache, rbstream->packetsize);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
available = len - skip;
|
||||
skip = 0;
|
||||
// Move to the end of the next packet.
|
||||
rbstream->address -= len;
|
||||
|
||||
rbstream->available = len - rbstream->skip;
|
||||
rbstream->skip = 0;
|
||||
}
|
||||
|
||||
unsigned int length = available;
|
||||
unsigned int length = rbstream->available;
|
||||
if (nbytes + length > size)
|
||||
length = size - nbytes;
|
||||
|
||||
offset -= length;
|
||||
available -= length;
|
||||
rbstream->available -= length;
|
||||
|
||||
memcpy (data + offset, rbstream->cache + available, length);
|
||||
memcpy (data + offset, rbstream->cache + rbstream->available, length);
|
||||
|
||||
// Update and emit a progress event.
|
||||
if (progress) {
|
||||
@ -160,13 +174,76 @@ dc_rbstream_read (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsign
|
||||
nbytes += length;
|
||||
}
|
||||
|
||||
rbstream->address = address;
|
||||
rbstream->available = available;
|
||||
rbstream->skip = skip;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_rbstream_read_forward (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsigned char data[], unsigned int size)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
while (nbytes < size) {
|
||||
if (rbstream->available == 0) {
|
||||
// Handle the ringbuffer wrap point.
|
||||
if (rbstream->address == rbstream->end)
|
||||
rbstream->address = rbstream->begin;
|
||||
|
||||
// Calculate the packet size.
|
||||
unsigned int len = rbstream->packetsize;
|
||||
if (rbstream->address + len > rbstream->end)
|
||||
len = rbstream->end - rbstream->address;
|
||||
|
||||
// Calculate the excess number of bytes.
|
||||
unsigned int extra = rbstream->packetsize - len;
|
||||
|
||||
// Read the packet into the cache.
|
||||
rc = dc_device_read (rbstream->device, rbstream->address - extra, rbstream->cache, rbstream->packetsize);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
// Move to the begin of the next packet.
|
||||
rbstream->address += len;
|
||||
|
||||
rbstream->offset = extra + rbstream->skip;
|
||||
rbstream->available = len - rbstream->skip;
|
||||
rbstream->skip = 0;
|
||||
}
|
||||
|
||||
unsigned int length = rbstream->available;
|
||||
if (nbytes + length > size)
|
||||
length = size - nbytes;
|
||||
|
||||
memcpy (data + nbytes, rbstream->cache + rbstream->offset, length);
|
||||
|
||||
rbstream->offset += length;
|
||||
rbstream->available -= length;
|
||||
|
||||
// Update and emit a progress event.
|
||||
if (progress) {
|
||||
progress->current += length;
|
||||
device_event_emit (rbstream->device, DC_EVENT_PROGRESS, progress);
|
||||
}
|
||||
|
||||
nbytes += length;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_rbstream_read (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsigned char data[], unsigned int size)
|
||||
{
|
||||
if (rbstream == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (rbstream->direction == DC_RBSTREAM_FORWARD) {
|
||||
return dc_rbstream_read_forward (rbstream, progress, data, size);
|
||||
} else {
|
||||
return dc_rbstream_read_backward (rbstream, progress, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_rbstream_free (dc_rbstream_t *rbstream)
|
||||
{
|
||||
|
||||
@ -33,6 +33,14 @@ extern "C" {
|
||||
*/
|
||||
typedef struct dc_rbstream_t dc_rbstream_t;
|
||||
|
||||
/**
|
||||
* The ringbuffer read direction.
|
||||
*/
|
||||
typedef enum dc_rbstream_direction_t {
|
||||
DC_RBSTREAM_FORWARD,
|
||||
DC_RBSTREAM_BACKWARD
|
||||
} dc_rbstream_direction_t;
|
||||
|
||||
/**
|
||||
* Create a new ringbuffer stream.
|
||||
*
|
||||
@ -43,11 +51,12 @@ typedef struct dc_rbstream_t dc_rbstream_t;
|
||||
* @param[in] begin The ringbuffer begin address.
|
||||
* @param[in] end The ringbuffer end address.
|
||||
* @param[in] address The stream start address.
|
||||
* @param[in] direction The ringbuffer read direction.
|
||||
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
|
||||
* on failure.
|
||||
*/
|
||||
dc_status_t
|
||||
dc_rbstream_new (dc_rbstream_t **rbstream, dc_device_t *device, unsigned int pagesize, unsigned int packetsize, unsigned int begin, unsigned int end, unsigned int address);
|
||||
dc_rbstream_new (dc_rbstream_t **rbstream, dc_device_t *device, unsigned int pagesize, unsigned int packetsize, unsigned int begin, unsigned int end, unsigned int address, dc_rbstream_direction_t direction);
|
||||
|
||||
/**
|
||||
* Read data from the ringbuffer stream.
|
||||
|
||||
@ -36,7 +36,7 @@ dc_status_t
|
||||
reefnet_sensus_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
|
||||
|
||||
dc_status_t
|
||||
reefnet_sensus_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int devtime, dc_ticks_t systime);
|
||||
reefnet_sensus_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -48,7 +48,6 @@ struct reefnet_sensus_parser_t {
|
||||
unsigned int maxdepth;
|
||||
};
|
||||
|
||||
static dc_status_t reefnet_sensus_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
|
||||
static dc_status_t reefnet_sensus_parser_set_clock (dc_parser_t *abstract, unsigned int devtime, dc_ticks_t systime);
|
||||
static dc_status_t reefnet_sensus_parser_set_atmospheric (dc_parser_t *abstract, double atmospheric);
|
||||
static dc_status_t reefnet_sensus_parser_set_density (dc_parser_t *abstract, double density);
|
||||
@ -59,7 +58,6 @@ static dc_status_t reefnet_sensus_parser_samples_foreach (dc_parser_t *abstract,
|
||||
static const dc_parser_vtable_t reefnet_sensus_parser_vtable = {
|
||||
sizeof(reefnet_sensus_parser_t),
|
||||
DC_FAMILY_REEFNET_SENSUS,
|
||||
reefnet_sensus_parser_set_data, /* set_data */
|
||||
reefnet_sensus_parser_set_clock, /* set_clock */
|
||||
reefnet_sensus_parser_set_atmospheric, /* set_atmospheric */
|
||||
reefnet_sensus_parser_set_density, /* set_density */
|
||||
@ -71,7 +69,7 @@ static const dc_parser_vtable_t reefnet_sensus_parser_vtable = {
|
||||
|
||||
|
||||
dc_status_t
|
||||
reefnet_sensus_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int devtime, dc_ticks_t systime)
|
||||
reefnet_sensus_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size)
|
||||
{
|
||||
reefnet_sensus_parser_t *parser = NULL;
|
||||
|
||||
@ -79,7 +77,7 @@ reefnet_sensus_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
parser = (reefnet_sensus_parser_t *) dc_parser_allocate (context, &reefnet_sensus_parser_vtable);
|
||||
parser = (reefnet_sensus_parser_t *) dc_parser_allocate (context, &reefnet_sensus_parser_vtable, data, size);
|
||||
if (parser == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
@ -88,8 +86,8 @@ reefnet_sensus_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
|
||||
// Set the default values.
|
||||
parser->atmospheric = DEF_ATMOSPHERIC;
|
||||
parser->hydrostatic = DEF_DENSITY_SALT * GRAVITY;
|
||||
parser->devtime = devtime;
|
||||
parser->systime = systime;
|
||||
parser->devtime = 0;
|
||||
parser->systime = 0;
|
||||
parser->cached = 0;
|
||||
parser->divetime = 0;
|
||||
parser->maxdepth = 0;
|
||||
@ -100,35 +98,6 @@ reefnet_sensus_parser_create (dc_parser_t **out, dc_context_t *context, unsigned
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
reefnet_sensus_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
reefnet_sensus_parser_t *parser = (reefnet_sensus_parser_t*) abstract;
|
||||
|
||||
// Reset the cache.
|
||||
parser->cached = 0;
|
||||
parser->divetime = 0;
|
||||
parser->maxdepth = 0;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
dc_status_t
|
||||
reefnet_sensus_parser_set_calibration (dc_parser_t *abstract, double atmospheric, double hydrostatic)
|
||||
{
|
||||
reefnet_sensus_parser_t *parser = (reefnet_sensus_parser_t*) abstract;
|
||||
|
||||
if (!ISINSTANCE (abstract))
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
parser->atmospheric = atmospheric;
|
||||
parser->hydrostatic = hydrostatic;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static dc_status_t
|
||||
reefnet_sensus_parser_set_clock (dc_parser_t *abstract, unsigned int devtime, dc_ticks_t systime)
|
||||
{
|
||||
@ -279,13 +248,13 @@ reefnet_sensus_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
|
||||
// Time (seconds)
|
||||
time += interval;
|
||||
sample.time = time;
|
||||
if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
|
||||
sample.time = time * 1000;
|
||||
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata);
|
||||
|
||||
// Depth (adjusted feet of seawater).
|
||||
unsigned int depth = data[offset++];
|
||||
sample.depth = ((depth + 33.0 - (double) SAMPLE_DEPTH_ADJUST) * FSW - parser->atmospheric) / parser->hydrostatic;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Temperature (degrees Fahrenheit)
|
||||
if ((nsamples % 6) == 0) {
|
||||
@ -293,7 +262,7 @@ reefnet_sensus_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
unsigned int temperature = data[offset++];
|
||||
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);
|
||||
}
|
||||
|
||||
// Current sample is complete.
|
||||
|
||||
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