Compare commits

..

2 Commits

Author SHA1 Message Date
Michael Keller
bb987642e3 Fix the OSTC4 firmware upgrade
In commit 1c8cd096b57a876c4fb0afc5113aac05d75d924e the block size was
changed from 64 to 1024 bytes. For bluetooth classic communication, this
shouldn't matter, but for some reason it does cause the OSTC4 firmware
upgrade to fail. Maybe some buffering problem in the OSTC4 firmware or
bluetooth stack?

Change the block size back to 64 bytes.
2023-07-07 15:01:13 +02:00
Jef Driesen
baa6944697 Post release version bump to 0.8.1 2023-05-11 18:56:37 +02:00
144 changed files with 2353 additions and 3503 deletions

View File

@ -19,7 +19,7 @@ jobs:
CC: ${{ matrix.compiler }} CC: ${{ matrix.compiler }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: sudo apt-get install libbluetooth-dev libusb-1.0-0-dev run: sudo apt-get install libbluetooth-dev libusb-1.0-0-dev
- run: autoreconf --install --force - run: autoreconf --install --force
@ -30,7 +30,7 @@ jobs:
run: | run: |
make install DESTDIR=$PWD/artifacts make install DESTDIR=$PWD/artifacts
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v3
with: with:
name: ${{ github.job }}-${{ matrix.compiler }} name: ${{ github.job }}-${{ matrix.compiler }}
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
@ -50,7 +50,7 @@ jobs:
CC: ${{ matrix.compiler }} CC: ${{ matrix.compiler }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: brew install autoconf automake libtool hidapi libusb run: brew install autoconf automake libtool hidapi libusb
- run: autoreconf --install --force - run: autoreconf --install --force
@ -61,7 +61,7 @@ jobs:
run: | run: |
make install DESTDIR=$PWD/artifacts make install DESTDIR=$PWD/artifacts
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v3
with: with:
name: ${{ github.job }}-${{ matrix.compiler }} name: ${{ github.job }}-${{ matrix.compiler }}
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
@ -78,7 +78,7 @@ jobs:
arch: [i686, x86_64] arch: [i686, x86_64]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Install dependencies - name: Install dependencies
run: sudo apt-get install gcc-mingw-w64 binutils-mingw-w64 mingw-w64-tools run: sudo apt-get install gcc-mingw-w64 binutils-mingw-w64 mingw-w64-tools
- name: Install libusb - name: Install libusb
@ -118,7 +118,7 @@ jobs:
run: | run: |
make install DESTDIR=$PWD/artifacts make install DESTDIR=$PWD/artifacts
tar -czf ${{ github.job }}-${{ matrix.arch }}.tar.gz -C artifacts usr tar -czf ${{ github.job }}-${{ matrix.arch }}.tar.gz -C artifacts usr
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v3
with: with:
name: ${{ github.job }}-${{ matrix.arch }} name: ${{ github.job }}-${{ matrix.arch }}
path: ${{ github.job }}-${{ matrix.arch }}.tar.gz path: ${{ github.job }}-${{ matrix.arch }}.tar.gz
@ -138,7 +138,7 @@ jobs:
CONFIGURATION: Release CONFIGURATION: Release
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- uses: msys2/setup-msys2@v2 - uses: msys2/setup-msys2@v2
with: with:
install: autoconf automake libtool pkg-config make gcc install: autoconf automake libtool pkg-config make gcc
@ -147,9 +147,9 @@ jobs:
./configure --prefix=/usr ./configure --prefix=/usr
make -C src revision.h make -C src revision.h
shell: msys2 {0} shell: msys2 {0}
- uses: microsoft/setup-msbuild@v2 - uses: microsoft/setup-msbuild@v1
- run: msbuild -m -p:Platform=${{ matrix.platform }} -p:Configuration=${{ env.CONFIGURATION }} contrib/msvc/libdivecomputer.vcxproj - run: msbuild -m -p:Platform=${{ matrix.platform }} -p:Configuration=${{ env.CONFIGURATION }} contrib/msvc/libdivecomputer.vcxproj
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v3
with: with:
name: ${{ github.job }}-${{ matrix.platform }} name: ${{ github.job }}-${{ matrix.platform }}
path: contrib/msvc/${{ matrix.platform }}/${{ env.CONFIGURATION }}/bin path: contrib/msvc/${{ matrix.platform }}/${{ env.CONFIGURATION }}/bin
@ -161,13 +161,13 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- run: | - run: |
autoreconf --install --force autoreconf --install --force
./configure --prefix=/usr ./configure --prefix=/usr
make -C src revision.h make -C src revision.h
- run: $ANDROID_NDK/ndk-build -C contrib/android NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk - run: $ANDROID_NDK/ndk-build -C contrib/android NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v3
with: with:
name: ${{ github.job }} name: ${{ github.job }}
path: contrib/android/libs path: contrib/android/libs

View File

@ -9,7 +9,7 @@ jobs:
name: Release name: Release
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Version number - name: Version number
id: version id: version

View File

@ -1,7 +1,7 @@
# Versioning. # Versioning.
m4_define([dc_version_major],[0]) m4_define([dc_version_major],[0])
m4_define([dc_version_minor],[9]) m4_define([dc_version_minor],[8])
m4_define([dc_version_micro],[0]) m4_define([dc_version_micro],[1])
m4_define([dc_version_suffix],[devel]) m4_define([dc_version_suffix],[devel])
m4_define([dc_version],dc_version_major.dc_version_minor.dc_version_micro[]m4_ifset([dc_version_suffix],-[dc_version_suffix])) m4_define([dc_version],dc_version_major.dc_version_minor.dc_version_micro[]m4_ifset([dc_version_suffix],-[dc_version_suffix]))

View File

@ -71,7 +71,6 @@ LOCAL_SRC_FILES := \
src/oceans_s1_parser.c \ src/oceans_s1_parser.c \
src/packet.c \ src/packet.c \
src/parser.c \ src/parser.c \
src/pelagic_i330r.c \
src/platform.c \ src/platform.c \
src/rbstream.c \ src/rbstream.c \
src/reefnet_sensus.c \ src/reefnet_sensus.c \

View File

@ -239,7 +239,6 @@
<ClCompile Include="..\..\src\oceans_s1_parser.c" /> <ClCompile Include="..\..\src\oceans_s1_parser.c" />
<ClCompile Include="..\..\src\packet.c" /> <ClCompile Include="..\..\src\packet.c" />
<ClCompile Include="..\..\src\parser.c" /> <ClCompile Include="..\..\src\parser.c" />
<ClCompile Include="..\..\src\pelagic_i330r.c" />
<ClCompile Include="..\..\src\platform.c" /> <ClCompile Include="..\..\src\platform.c" />
<ClCompile Include="..\..\src\rbstream.c" /> <ClCompile Include="..\..\src\rbstream.c" />
<ClCompile Include="..\..\src\reefnet_sensus.c" /> <ClCompile Include="..\..\src\reefnet_sensus.c" />
@ -332,6 +331,7 @@
<ClInclude Include="..\..\src\cressi_leonardo.h" /> <ClInclude Include="..\..\src\cressi_leonardo.h" />
<ClInclude Include="..\..\src\deepblu_cosmiq.h" /> <ClInclude Include="..\..\src\deepblu_cosmiq.h" />
<ClInclude Include="..\..\src\deepsix_excursion.h" /> <ClInclude Include="..\..\src\deepsix_excursion.h" />
<ClInclude Include="..\..\src\descriptor-private.h" />
<ClInclude Include="..\..\src\device-private.h" /> <ClInclude Include="..\..\src\device-private.h" />
<ClInclude Include="..\..\src\diverite_nitekq.h" /> <ClInclude Include="..\..\src\diverite_nitekq.h" />
<ClInclude Include="..\..\src\divesoft_freedom.h" /> <ClInclude Include="..\..\src\divesoft_freedom.h" />
@ -358,7 +358,6 @@
<ClInclude Include="..\..\src\oceans_s1_common.h" /> <ClInclude Include="..\..\src\oceans_s1_common.h" />
<ClInclude Include="..\..\src\packet.h" /> <ClInclude Include="..\..\src\packet.h" />
<ClInclude Include="..\..\src\parser-private.h" /> <ClInclude Include="..\..\src\parser-private.h" />
<ClInclude Include="..\..\src\pelagic_i330r.h" />
<ClInclude Include="..\..\src\platform.h" /> <ClInclude Include="..\..\src\platform.h" />
<ClInclude Include="..\..\src\rbstream.h" /> <ClInclude Include="..\..\src\rbstream.h" />
<ClInclude Include="..\..\src\reefnet_sensus.h" /> <ClInclude Include="..\..\src\reefnet_sensus.h" />

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,65 @@
.\"
.\" libdivecomputer
.\"
.\" Copyright (C) 2017 Kristaps Dzonsons <kristaps@bsd.lv>
.\"
.\" This library is free software; you can redistribute it and/or
.\" modify it under the terms of the GNU Lesser General Public
.\" License as published by the Free Software Foundation; either
.\" version 2.1 of the License, or (at your option) any later version.
.\"
.\" This library is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
.\" Lesser General Public License for more details.
.\"
.\" You should have received a copy of the GNU Lesser General Public
.\" License along with this library; if not, write to the Free Software
.\" Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
.\" MA 02110-1301 USA
.\"
.Dd January 5, 2017
.Dt DC_PARSER_SET_DATA 3
.Os
.Sh NAME
.Nm dc_parser_set_data
.Nd assigns parse data to a dive parser
.Sh LIBRARY
.Lb libdivecomputer
.Sh SYNOPSIS
.In libdivecomputer/parser.h
.Ft dc_status_t
.Fo dc_parser_set_data
.Fa "dc_parser_t *parser"
.Fa "const unsigned char *data"
.Fa "unsigned int size"
.Fc
.Sh DESCRIPTION
Assigns the binary sequence
.Fa data
of length
.Fa size
bytes to
.Fa parser ,
which was created with
.Xr dc_parser_new 3 .
How the data is parsed depends upon the values provided to
.Xr dc_parser_new 3 .
The data usually comes from the callback assigned to
.Xr dc_device_foreach 3 .
.Sh RETURN VALUES
Returns
.Dv DC_STATUS_OK
on success and another code on failure.
.Sh SEE ALSO
.Xr dc_device_foreach 3 ,
.Xr dc_parser_new 3
.Sh AUTHORS
The
.Lb libdivecomputer
library was written by
.An Jef Driesen ,
.Mt jef@libdivecomputer.org .
The manpages were written by
.An Kristaps Dzonsons ,
.Mt kristaps@bsd.lv .

View File

@ -82,7 +82,9 @@ Iterate over all dives with
.Xr dc_device_foreach 3 . .Xr dc_device_foreach 3 .
.It .It
For each iterated dive, create a new parser with For each iterated dive, create a new parser with
.Xr dc_parser_new 3 . .Xr dc_parser_new 3
and set the parsed data with
.Xr dc_parser_set_data 3 .
.It .It
Get attributes of the parsed dive with Get attributes of the parsed dive with
.Xr dc_parser_get_field 3 . .Xr dc_parser_get_field 3 .

View File

@ -72,7 +72,6 @@ static const backend_table_t g_backends[] = {
{"vtpro", DC_FAMILY_OCEANIC_VTPRO, 0x4245}, {"vtpro", DC_FAMILY_OCEANIC_VTPRO, 0x4245},
{"veo250", DC_FAMILY_OCEANIC_VEO250, 0x424C}, {"veo250", DC_FAMILY_OCEANIC_VEO250, 0x424C},
{"atom2", DC_FAMILY_OCEANIC_ATOM2, 0x4342}, {"atom2", DC_FAMILY_OCEANIC_ATOM2, 0x4342},
{"i330r", DC_FAMILY_PELAGIC_I330R, 0x4744},
{"nemo", DC_FAMILY_MARES_NEMO, 0}, {"nemo", DC_FAMILY_MARES_NEMO, 0},
{"puck", DC_FAMILY_MARES_PUCK, 7}, {"puck", DC_FAMILY_MARES_PUCK, 7},
{"darwin", DC_FAMILY_MARES_DARWIN, 0}, {"darwin", DC_FAMILY_MARES_DARWIN, 0},

View File

@ -80,12 +80,20 @@ dive_cb (const unsigned char *data, unsigned int size, const unsigned char *fing
// Create the parser. // Create the parser.
message ("Creating the parser.\n"); message ("Creating the parser.\n");
rc = dc_parser_new (&parser, divedata->device, data, size); rc = dc_parser_new (&parser, divedata->device);
if (rc != DC_STATUS_SUCCESS) { if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error creating the parser."); ERROR ("Error creating the parser.");
goto cleanup; goto cleanup;
} }
// Register the data.
message ("Registering the data.\n");
rc = dc_parser_set_data (parser, data, size);
if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error registering the data.");
goto cleanup;
}
// Parse the dive data. // Parse the dive data.
message ("Parsing the dive data.\n"); message ("Parsing the dive data.\n");
rc = dctool_output_write (divedata->output, parser, data, size, fingerprint, fsize); rc = dctool_output_write (divedata->output, parser, data, size, fingerprint, fsize);

View File

@ -54,17 +54,17 @@ parse (dc_buffer_t *buffer, dc_context_t *context, dc_descriptor_t *descriptor,
// Create the parser. // Create the parser.
message ("Creating the parser.\n"); message ("Creating the parser.\n");
rc = dc_parser_new2 (&parser, context, descriptor, data, size); rc = dc_parser_new2 (&parser, context, descriptor, devtime, systime);
if (rc != DC_STATUS_SUCCESS) { if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error creating the parser."); ERROR ("Error creating the parser.");
goto cleanup; goto cleanup;
} }
// Set the clock. // Register the data.
message ("Setting the clock.\n"); message ("Registering the data.\n");
rc = dc_parser_set_clock (parser, devtime, systime); rc = dc_parser_set_data (parser, data, size);
if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { if (rc != DC_STATUS_SUCCESS) {
ERROR ("Error setting the clock."); ERROR ("Error registering the data.");
goto cleanup; goto cleanup;
} }

View File

@ -90,7 +90,7 @@ convert_volume (double value, dctool_units_t units)
} }
static void static void
sample_cb (dc_sample_type_t type, const dc_sample_value_t *value, void *userdata) sample_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata)
{ {
static const char *events[] = { static const char *events[] = {
"none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter", "none", "deco", "rbt", "ascent", "ceiling", "workload", "transmitter",
@ -104,80 +104,64 @@ sample_cb (dc_sample_type_t type, const dc_sample_value_t *value, void *userdata
sample_data_t *sampledata = (sample_data_t *) userdata; sample_data_t *sampledata = (sample_data_t *) userdata;
unsigned int seconds = 0, milliseconds = 0;
switch (type) { switch (type) {
case DC_SAMPLE_TIME: case DC_SAMPLE_TIME:
seconds = value->time / 1000;
milliseconds = value->time % 1000;
if (sampledata->nsamples++) if (sampledata->nsamples++)
fprintf (sampledata->ostream, "</sample>\n"); fprintf (sampledata->ostream, "</sample>\n");
fprintf (sampledata->ostream, "<sample>\n"); fprintf (sampledata->ostream, "<sample>\n");
if (milliseconds) { fprintf (sampledata->ostream, " <time>%02u:%02u</time>\n", value.time / 60, value.time % 60);
fprintf (sampledata->ostream, " <time>%02u:%02u.%03u</time>\n", seconds / 60, seconds % 60, milliseconds);
} else {
fprintf (sampledata->ostream, " <time>%02u:%02u</time>\n", seconds / 60, seconds % 60);
}
break; break;
case DC_SAMPLE_DEPTH: case DC_SAMPLE_DEPTH:
fprintf (sampledata->ostream, " <depth>%.2f</depth>\n", fprintf (sampledata->ostream, " <depth>%.2f</depth>\n",
convert_depth(value->depth, sampledata->units)); convert_depth(value.depth, sampledata->units));
break; break;
case DC_SAMPLE_PRESSURE: case DC_SAMPLE_PRESSURE:
fprintf (sampledata->ostream, " <pressure tank=\"%u\">%.2f</pressure>\n", fprintf (sampledata->ostream, " <pressure tank=\"%u\">%.2f</pressure>\n",
value->pressure.tank, value.pressure.tank,
convert_pressure(value->pressure.value, sampledata->units)); convert_pressure(value.pressure.value, sampledata->units));
break; break;
case DC_SAMPLE_TEMPERATURE: case DC_SAMPLE_TEMPERATURE:
fprintf (sampledata->ostream, " <temperature>%.2f</temperature>\n", fprintf (sampledata->ostream, " <temperature>%.2f</temperature>\n",
convert_temperature(value->temperature, sampledata->units)); convert_temperature(value.temperature, sampledata->units));
break; break;
case DC_SAMPLE_EVENT: case DC_SAMPLE_EVENT:
if (value->event.type != SAMPLE_EVENT_GASCHANGE && value->event.type != SAMPLE_EVENT_GASCHANGE2) { if (value.event.type != SAMPLE_EVENT_GASCHANGE && value.event.type != SAMPLE_EVENT_GASCHANGE2) {
fprintf (sampledata->ostream, " <event type=\"%u\" time=\"%u\" flags=\"%u\" value=\"%u\">%s</event>\n", fprintf (sampledata->ostream, " <event type=\"%u\" time=\"%u\" flags=\"%u\" value=\"%u\">%s</event>\n",
value->event.type, value->event.time, value->event.flags, value->event.value, events[value->event.type]); value.event.type, value.event.time, value.event.flags, value.event.value, events[value.event.type]);
} }
break; break;
case DC_SAMPLE_RBT: case DC_SAMPLE_RBT:
fprintf (sampledata->ostream, " <rbt>%u</rbt>\n", value->rbt); fprintf (sampledata->ostream, " <rbt>%u</rbt>\n", value.rbt);
break; break;
case DC_SAMPLE_HEARTBEAT: case DC_SAMPLE_HEARTBEAT:
fprintf (sampledata->ostream, " <heartbeat>%u</heartbeat>\n", value->heartbeat); fprintf (sampledata->ostream, " <heartbeat>%u</heartbeat>\n", value.heartbeat);
break; break;
case DC_SAMPLE_BEARING: case DC_SAMPLE_BEARING:
fprintf (sampledata->ostream, " <bearing>%u</bearing>\n", value->bearing); fprintf (sampledata->ostream, " <bearing>%u</bearing>\n", value.bearing);
break; break;
case DC_SAMPLE_VENDOR: case DC_SAMPLE_VENDOR:
fprintf (sampledata->ostream, " <vendor type=\"%u\" size=\"%u\">", value->vendor.type, value->vendor.size); fprintf (sampledata->ostream, " <vendor type=\"%u\" size=\"%u\">", value.vendor.type, value.vendor.size);
for (unsigned int i = 0; i < value->vendor.size; ++i) for (unsigned int i = 0; i < value.vendor.size; ++i)
fprintf (sampledata->ostream, "%02X", ((const unsigned char *) value->vendor.data)[i]); fprintf (sampledata->ostream, "%02X", ((const unsigned char *) value.vendor.data)[i]);
fprintf (sampledata->ostream, "</vendor>\n"); fprintf (sampledata->ostream, "</vendor>\n");
break; break;
case DC_SAMPLE_SETPOINT: case DC_SAMPLE_SETPOINT:
fprintf (sampledata->ostream, " <setpoint>%.2f</setpoint>\n", value->setpoint); fprintf (sampledata->ostream, " <setpoint>%.2f</setpoint>\n", value.setpoint);
break; break;
case DC_SAMPLE_PPO2: case DC_SAMPLE_PPO2:
if (value->ppo2.sensor != DC_SENSOR_NONE) { fprintf (sampledata->ostream, " <ppo2>%.2f</ppo2>\n", value.ppo2);
fprintf (sampledata->ostream, " <ppo2 sensor=\"%u\">%.2f</ppo2>\n", value->ppo2.sensor, value->ppo2.value);
} else {
fprintf (sampledata->ostream, " <ppo2>%.2f</ppo2>\n", value->ppo2.value);
}
break; break;
case DC_SAMPLE_CNS: case DC_SAMPLE_CNS:
fprintf (sampledata->ostream, " <cns>%.1f</cns>\n", value->cns * 100.0); fprintf (sampledata->ostream, " <cns>%.1f</cns>\n", value.cns * 100.0);
break; break;
case DC_SAMPLE_DECO: case DC_SAMPLE_DECO:
fprintf (sampledata->ostream, " <deco time=\"%u\" depth=\"%.2f\">%s</deco>\n", fprintf (sampledata->ostream, " <deco time=\"%u\" depth=\"%.2f\">%s</deco>\n",
value->deco.time, value.deco.time,
convert_depth(value->deco.depth, sampledata->units), convert_depth(value.deco.depth, sampledata->units),
decostop[value->deco.type]); decostop[value.deco.type]);
if (value->deco.tts) {
fprintf (sampledata->ostream, " <tts>%u</tts>\n",
value->deco.tts);
}
break; break;
case DC_SAMPLE_GASMIX: case DC_SAMPLE_GASMIX:
fprintf (sampledata->ostream, " <gasmix>%u</gasmix>\n", value->gasmix); fprintf (sampledata->ostream, " <gasmix>%u</gasmix>\n", value.gasmix);
break; break;
default: default:
break; break;
@ -338,19 +322,11 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
"<gasmix>\n" "<gasmix>\n"
" <he>%.1f</he>\n" " <he>%.1f</he>\n"
" <o2>%.1f</o2>\n" " <o2>%.1f</o2>\n"
" <n2>%.1f</n2>\n", " <n2>%.1f</n2>\n"
"</gasmix>\n",
gasmix.helium * 100.0, gasmix.helium * 100.0,
gasmix.oxygen * 100.0, gasmix.oxygen * 100.0,
gasmix.nitrogen * 100.0); gasmix.nitrogen * 100.0);
if (gasmix.usage) {
const char *usage[] = {"none", "oxygen", "diluent", "sidemount"};
fprintf (output->ostream,
" <usage>%s</usage>\n",
usage[gasmix.usage]);
}
fprintf (output->ostream,
"</gasmix>\n");
} }
// Parse the tanks. // Parse the tanks.
@ -378,12 +354,6 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
" <gasmix>%u</gasmix>\n", " <gasmix>%u</gasmix>\n",
tank.gasmix); tank.gasmix);
} }
if (tank.usage) {
const char *usage[] = {"none", "oxygen", "diluent", "sidemount"};
fprintf (output->ostream,
" <usage>%s</usage>\n",
usage[tank.usage]);
}
if (tank.type != DC_TANKVOLUME_NONE) { if (tank.type != DC_TANKVOLUME_NONE) {
fprintf (output->ostream, fprintf (output->ostream,
" <type>%s</type>\n" " <type>%s</type>\n"
@ -450,14 +420,8 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
} }
if (status != DC_STATUS_UNSUPPORTED) { if (status != DC_STATUS_UNSUPPORTED) {
const char *names[] = {"fresh", "salt"}; fprintf (output->ostream, "<salinity type=\"%u\">%.1f</salinity>\n",
if (salinity.density) { salinity.type, salinity.density);
fprintf (output->ostream, "<salinity density=\"%.1f\">%s</salinity>\n",
salinity.density, names[salinity.type]);
} else {
fprintf (output->ostream, "<salinity>%s</salinity>\n",
names[salinity.type]);
}
} }
// Parse the atmospheric pressure. // Parse the atmospheric pressure.

View File

@ -36,6 +36,9 @@ atomics_cobalt_device_version (dc_device_t *device, unsigned char data[], unsign
dc_status_t dc_status_t
atomics_cobalt_device_set_simulation (dc_device_t *device, unsigned int simulation); atomics_cobalt_device_set_simulation (dc_device_t *device, unsigned int simulation);
dc_status_t
atomics_cobalt_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -33,21 +33,6 @@ extern "C" {
*/ */
#define DC_IOCTL_BLE_GET_NAME DC_IOCTL_IOR('b', 0, DC_IOCTL_SIZE_VARIABLE) #define DC_IOCTL_BLE_GET_NAME DC_IOCTL_IOR('b', 0, DC_IOCTL_SIZE_VARIABLE)
/**
* Get the bluetooth authentication PIN code.
*
* The data format is a NULL terminated string.
*/
#define DC_IOCTL_BLE_GET_PINCODE DC_IOCTL_IOR('b', 1, DC_IOCTL_SIZE_VARIABLE)
/**
* Get/set the bluetooth authentication access code.
*
* The data format is a variable sized byte array.
*/
#define DC_IOCTL_BLE_GET_ACCESSCODE DC_IOCTL_IOR('b', 2, DC_IOCTL_SIZE_VARIABLE)
#define DC_IOCTL_BLE_SET_ACCESSCODE DC_IOCTL_IOW('b', 2, DC_IOCTL_SIZE_VARIABLE)
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -74,7 +74,6 @@ typedef enum dc_family_t {
DC_FAMILY_OCEANIC_VTPRO = (4 << 16), DC_FAMILY_OCEANIC_VTPRO = (4 << 16),
DC_FAMILY_OCEANIC_VEO250, DC_FAMILY_OCEANIC_VEO250,
DC_FAMILY_OCEANIC_ATOM2, DC_FAMILY_OCEANIC_ATOM2,
DC_FAMILY_PELAGIC_I330R,
/* Mares */ /* Mares */
DC_FAMILY_MARES_NEMO = (5 << 16), DC_FAMILY_MARES_NEMO = (5 << 16),
DC_FAMILY_MARES_PUCK, DC_FAMILY_MARES_PUCK,

View File

@ -29,96 +29,29 @@
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
/**
* Opaque object representing a supported dive computer.
*/
typedef struct dc_descriptor_t dc_descriptor_t; typedef struct dc_descriptor_t dc_descriptor_t;
/**
* Create an iterator to enumerate the supported dive computers.
*
* @param[out] iterator A location to store the iterator.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t dc_status_t
dc_descriptor_iterator (dc_iterator_t **iterator); dc_descriptor_iterator (dc_iterator_t **iterator);
/**
* Free the device descriptor.
*
* @param[in] descriptor A valid device descriptor.
*/
void void
dc_descriptor_free (dc_descriptor_t *descriptor); dc_descriptor_free (dc_descriptor_t *descriptor);
/**
* Get the vendor name of the dive computer.
*
* @param[in] descriptor A valid device descriptor.
* @returns The vendor name of the dive computer on success, or NULL on failure.
*/
const char * const char *
dc_descriptor_get_vendor (dc_descriptor_t *descriptor); dc_descriptor_get_vendor (dc_descriptor_t *descriptor);
/**
* Get the product name of the dive computer.
*
* @param[in] descriptor A valid device descriptor.
* @returns The product name of the dive computer on success, or NULL on
* failure.
*/
const char * const char *
dc_descriptor_get_product (dc_descriptor_t *descriptor); dc_descriptor_get_product (dc_descriptor_t *descriptor);
/**
* Get the family type of the dive computer.
*
* @param[in] descriptor A valid device descriptor.
* @returns The family type of the dive computer on success, or DC_FAMILY_NULL
* on failure.
*/
dc_family_t dc_family_t
dc_descriptor_get_type (dc_descriptor_t *descriptor); dc_descriptor_get_type (dc_descriptor_t *descriptor);
/**
* Get the model number of the dive computer.
*
* @param[in] descriptor A valid device descriptor.
* @returns The model number of the dive computer on success, or zero on
* failure.
*/
unsigned int unsigned int
dc_descriptor_get_model (dc_descriptor_t *descriptor); dc_descriptor_get_model (dc_descriptor_t *descriptor);
/**
* Get all transports supported by the dive computer.
*
* @param[in] descriptor A valid device descriptor.
* @returns A bitmask with all the transports supported by the dive computer on
* success, or DC_TRANSPORT_NONE on failure.
*/
unsigned int unsigned int
dc_descriptor_get_transports (dc_descriptor_t *descriptor); dc_descriptor_get_transports (dc_descriptor_t *descriptor);
/**
* Check if a low-level I/O device matches a supported dive computer.
*
* @param[in] descriptor A valid device descriptor.
* @param[in] transport The transport type of the I/O device.
* @param[in] userdata A pointer to a transport specific data structure:
* - DC_TRANSPORT_SERIAL: Name of the device node (string)
* - DC_TRANSPORT_USB: USB VID/PID (#dc_usb_desc_t)
* - DC_TRANSPORT_USBHID: USB VID/PID (#dc_usbhid_desc_t)
* - DC_TRANSPORT_IRDA: IrDA device name (string)
* - DC_TRANSPORT_BLUETOOTH: Bluetooth device name (string)
* - DC_TRANSPORT_BLE: Bluetooth device name (string)
* @returns Non-zero if the device matches a supported dive computer, or zero if
* there is no match.
*/
int
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -141,21 +141,12 @@ typedef struct dc_salinity_t {
double density; double density;
} dc_salinity_t; } dc_salinity_t;
typedef enum dc_usage_t {
DC_USAGE_NONE,
DC_USAGE_OXYGEN,
DC_USAGE_DILUENT,
DC_USAGE_SIDEMOUNT,
} dc_usage_t;
typedef struct dc_gasmix_t { typedef struct dc_gasmix_t {
double helium; double helium;
double oxygen; double oxygen;
double nitrogen; double nitrogen;
dc_usage_t usage;
} dc_gasmix_t; } dc_gasmix_t;
#define DC_SENSOR_NONE 0xFFFFFFFF
#define DC_GASMIX_UNKNOWN 0xFFFFFFFF #define DC_GASMIX_UNKNOWN 0xFFFFFFFF
typedef enum dc_tankvolume_t { typedef enum dc_tankvolume_t {
@ -194,7 +185,6 @@ typedef struct dc_tank_t {
double workpressure; /* Work pressure (bar) */ double workpressure; /* Work pressure (bar) */
double beginpressure; /* Begin pressure (bar) */ double beginpressure; /* Begin pressure (bar) */
double endpressure; /* End pressure (bar) */ double endpressure; /* End pressure (bar) */
dc_usage_t usage;
} dc_tank_t; } dc_tank_t;
typedef enum dc_decomodel_type_t { typedef enum dc_decomodel_type_t {
@ -235,7 +225,7 @@ typedef struct dc_decomodel_t {
} dc_decomodel_t; } dc_decomodel_t;
typedef union dc_sample_value_t { typedef union dc_sample_value_t {
unsigned int time; /* Milliseconds */ unsigned int time;
double depth; double depth;
struct { struct {
unsigned int tank; unsigned int tank;
@ -257,29 +247,25 @@ typedef union dc_sample_value_t {
const void *data; const void *data;
} vendor; } vendor;
double setpoint; double setpoint;
struct { double ppo2;
unsigned int sensor;
double value;
} ppo2;
double cns; double cns;
struct { struct {
unsigned int type; unsigned int type;
unsigned int time; unsigned int time;
double depth; double depth;
unsigned int tts;
} deco; } deco;
unsigned int gasmix; /* Gas mix index */ unsigned int gasmix; /* Gas mix index */
} dc_sample_value_t; } dc_sample_value_t;
typedef struct dc_parser_t dc_parser_t; typedef struct dc_parser_t dc_parser_t;
typedef void (*dc_sample_callback_t) (dc_sample_type_t type, const dc_sample_value_t *value, void *userdata); typedef void (*dc_sample_callback_t) (dc_sample_type_t type, dc_sample_value_t value, void *userdata);
dc_status_t dc_status_t
dc_parser_new (dc_parser_t **parser, dc_device_t *device, const unsigned char data[], size_t size); dc_parser_new (dc_parser_t **parser, dc_device_t *device);
dc_status_t dc_status_t
dc_parser_new2 (dc_parser_t **parser, dc_context_t *context, dc_descriptor_t *descriptor, const unsigned char data[], size_t size); dc_parser_new2 (dc_parser_t **parser, dc_context_t *context, dc_descriptor_t *descriptor, unsigned int devtime, dc_ticks_t systime);
dc_family_t dc_family_t
dc_parser_get_type (dc_parser_t *parser); dc_parser_get_type (dc_parser_t *parser);
@ -293,6 +279,9 @@ dc_parser_set_atmospheric (dc_parser_t *parser, double atmospheric);
dc_status_t dc_status_t
dc_parser_set_density (dc_parser_t *parser, double density); 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_status_t
dc_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime); dc_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime);

View File

@ -35,6 +35,9 @@ extern "C" {
dc_status_t dc_status_t
reefnet_sensus_device_get_handshake (dc_device_t *device, unsigned char data[], unsigned int size); reefnet_sensus_device_get_handshake (dc_device_t *device, unsigned char data[], unsigned int size);
dc_status_t
reefnet_sensus_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -38,6 +38,9 @@ reefnet_sensuspro_device_get_handshake (dc_device_t *device, unsigned char data[
dc_status_t dc_status_t
reefnet_sensuspro_device_write_interval (dc_device_t *device, unsigned char interval); reefnet_sensuspro_device_write_interval (dc_device_t *device, unsigned char interval);
dc_status_t
reefnet_sensuspro_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -56,6 +56,9 @@ reefnet_sensusultra_device_write_parameter (dc_device_t *device, reefnet_sensusu
dc_status_t dc_status_t
reefnet_sensusultra_device_sense (dc_device_t *device, unsigned char data[], unsigned int size); reefnet_sensusultra_device_sense (dc_device_t *device, unsigned char data[], unsigned int size);
dc_status_t
reefnet_sensusultra_parser_set_calibration (dc_parser_t *parser, double atmospheric, double hydrostatic);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -86,14 +86,6 @@ typedef enum dc_usb_recipient_t {
DC_USB_RECIPIENT_OTHER = 0x03, DC_USB_RECIPIENT_OTHER = 0x03,
} dc_usb_recipient_t; } dc_usb_recipient_t;
/**
* USB device descriptor.
*/
typedef struct dc_usb_desc_t {
unsigned short vid;
unsigned short pid;
} dc_usb_desc_t;
/** /**
* Opaque object representing a USB device. * Opaque object representing a USB device.
*/ */

View File

@ -32,14 +32,6 @@
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
/**
* USB HID device descriptor.
*/
typedef struct dc_usbhid_desc_t {
unsigned short vid;
unsigned short pid;
} dc_usbhid_desc_t;
/** /**
* Opaque object representing a USB HID device. * Opaque object representing a USB HID device.
*/ */

View File

@ -16,7 +16,7 @@ endif
libdivecomputer_la_SOURCES = \ libdivecomputer_la_SOURCES = \
version.c \ version.c \
descriptor.c \ descriptor-private.h descriptor.c \
iostream-private.h iostream.c \ iostream-private.h iostream.c \
iterator-private.h iterator.c \ iterator-private.h iterator.c \
common-private.h common.c \ common-private.h common.c \
@ -43,7 +43,6 @@ libdivecomputer_la_SOURCES = \
oceanic_atom2.h oceanic_atom2.c oceanic_atom2_parser.c \ oceanic_atom2.h oceanic_atom2.c oceanic_atom2_parser.c \
oceanic_veo250.h oceanic_veo250.c oceanic_veo250_parser.c \ oceanic_veo250.h oceanic_veo250.c oceanic_veo250_parser.c \
oceanic_vtpro.h oceanic_vtpro.c oceanic_vtpro_parser.c \ oceanic_vtpro.h oceanic_vtpro.c oceanic_vtpro_parser.c \
pelagic_i330r.h pelagic_i330r.c \
mares_common.h mares_common.c \ mares_common.h mares_common.c \
mares_nemo.h mares_nemo.c mares_nemo_parser.c \ mares_nemo.h mares_nemo.c mares_nemo_parser.c \
mares_puck.h mares_puck.c \ mares_puck.h mares_puck.c \

View File

@ -404,14 +404,3 @@ signextend (unsigned int value, unsigned int nbits)
else else
return value & mask; return value & mask;
} }
unsigned int
popcount (unsigned int value)
{
unsigned int count = 0;
while (value) {
value &= value - 1;
count++;
}
return count;
}

View File

@ -126,9 +126,6 @@ dec2bcd (unsigned char value);
unsigned int unsigned int
signextend (unsigned int value, unsigned int nbits); signextend (unsigned int value, unsigned int nbits);
unsigned int
popcount (unsigned int value);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -41,8 +41,6 @@
#define FP_OFFSET 20 #define FP_OFFSET 20
#define SZ_HEADER 228
#define SZ_MEMORY1 (29 * 64 * 1024) // Cobalt 1 #define SZ_MEMORY1 (29 * 64 * 1024) // Cobalt 1
#define SZ_MEMORY2 (41 * 64 * 1024) // Cobalt 2 #define SZ_MEMORY2 (41 * 64 * 1024) // Cobalt 2
#define SZ_VERSION 14 #define SZ_VERSION 14
@ -349,12 +347,6 @@ atomics_cobalt_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
} }
if (size < SZ_HEADER) {
ERROR (abstract->context, "Dive header is too small (%u).", size);
dc_buffer_free (buffer);
return DC_STATUS_DATAFORMAT;
}
if (memcmp (data + FP_OFFSET, device->fingerprint, sizeof (device->fingerprint)) == 0) { if (memcmp (data + FP_OFFSET, device->fingerprint, sizeof (device->fingerprint)) == 0) {
dc_buffer_free (buffer); dc_buffer_free (buffer);
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;

View File

@ -36,7 +36,7 @@ dc_status_t
atomics_cobalt_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); atomics_cobalt_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
atomics_cobalt_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size); atomics_cobalt_parser_create (dc_parser_t **parser, dc_context_t *context);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -43,6 +43,7 @@ struct atomics_cobalt_parser_t {
double hydrostatic; double hydrostatic;
}; };
static dc_status_t atomics_cobalt_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
static dc_status_t atomics_cobalt_parser_set_density (dc_parser_t *abstract, double density); static dc_status_t atomics_cobalt_parser_set_density (dc_parser_t *abstract, double density);
static dc_status_t atomics_cobalt_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t atomics_cobalt_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
@ -51,6 +52,7 @@ static dc_status_t atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract,
static const dc_parser_vtable_t atomics_cobalt_parser_vtable = { static const dc_parser_vtable_t atomics_cobalt_parser_vtable = {
sizeof(atomics_cobalt_parser_t), sizeof(atomics_cobalt_parser_t),
DC_FAMILY_ATOMICS_COBALT, DC_FAMILY_ATOMICS_COBALT,
atomics_cobalt_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
atomics_cobalt_parser_set_density, /* set_density */ atomics_cobalt_parser_set_density, /* set_density */
@ -62,7 +64,7 @@ static const dc_parser_vtable_t atomics_cobalt_parser_vtable = {
dc_status_t dc_status_t
atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size) atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context)
{ {
atomics_cobalt_parser_t *parser = NULL; atomics_cobalt_parser_t *parser = NULL;
@ -70,7 +72,7 @@ atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context, const un
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (atomics_cobalt_parser_t *) dc_parser_allocate (context, &atomics_cobalt_parser_vtable, data, size); parser = (atomics_cobalt_parser_t *) dc_parser_allocate (context, &atomics_cobalt_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -85,6 +87,27 @@ atomics_cobalt_parser_create (dc_parser_t **out, dc_context_t *context, const un
} }
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 static dc_status_t
atomics_cobalt_parser_set_density (dc_parser_t *abstract, double density) atomics_cobalt_parser_set_density (dc_parser_t *abstract, double density)
{ {
@ -148,7 +171,6 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
*((unsigned int *) value) = p[0x2a]; *((unsigned int *) value) = p[0x2a];
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = p[SZ_HEADER + SZ_GASMIX * flags + 5] / 100.0; gasmix->helium = p[SZ_HEADER + SZ_GASMIX * flags + 5] / 100.0;
gasmix->oxygen = p[SZ_HEADER + SZ_GASMIX * flags + 4] / 100.0; gasmix->oxygen = p[SZ_HEADER + SZ_GASMIX * flags + 4] / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -180,7 +202,6 @@ atomics_cobalt_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
tank->gasmix = flags; tank->gasmix = flags;
tank->beginpressure = array_uint16_le(p + 6) * PSI / BAR; tank->beginpressure = array_uint16_le(p + 6) * PSI / BAR;
tank->endpressure = array_uint16_le(p + 14) * PSI / BAR; tank->endpressure = array_uint16_le(p + 14) * PSI / BAR;
tank->usage = DC_USAGE_NONE;
break; break;
case DC_FIELD_DIVEMODE: case DC_FIELD_DIVEMODE:
switch(p[0x24]) { switch(p[0x24]) {
@ -255,19 +276,19 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
// Time (seconds). // Time (seconds).
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/1000 bar). // Depth (1/1000 bar).
unsigned int depth = array_uint16_le (data + offset + 0); unsigned int depth = array_uint16_le (data + offset + 0);
sample.depth = (signed int)(depth - atmospheric) * (BAR / 1000.0) / parser->hydrostatic; sample.depth = (signed int)(depth - atmospheric) * (BAR / 1000.0) / parser->hydrostatic;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Pressure (1 psi). // Pressure (1 psi).
unsigned int pressure = array_uint16_le (data + offset + 2); unsigned int pressure = array_uint16_le (data + offset + 2);
sample.pressure.tank = tank; sample.pressure.tank = tank;
sample.pressure.value = pressure * PSI / BAR; sample.pressure.value = pressure * PSI / BAR;
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata); if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
// Current gas mix // Current gas mix
unsigned int gasmix = data[offset + 4]; unsigned int gasmix = data[offset + 4];
@ -283,14 +304,14 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
sample.gasmix = idx; sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix_previous = gasmix; gasmix_previous = gasmix;
} }
// Temperature (1 °F). // Temperature (1 °F).
unsigned int temperature = data[offset + 8]; unsigned int temperature = data[offset + 8];
sample.temperature = (temperature - 32.0) * (5.0 / 9.0); sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
// violation status // violation status
sample.event.type = 0; sample.event.type = 0;
@ -300,15 +321,15 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
unsigned int violation = data[offset + 11]; unsigned int violation = data[offset + 11];
if (violation & 0x01) { if (violation & 0x01) {
sample.event.type = SAMPLE_EVENT_ASCENT; sample.event.type = SAMPLE_EVENT_ASCENT;
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
} }
if (violation & 0x04) { if (violation & 0x04) {
sample.event.type = SAMPLE_EVENT_CEILING; sample.event.type = SAMPLE_EVENT_CEILING;
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
} }
if (violation & 0x08) { if (violation & 0x08) {
sample.event.type = SAMPLE_EVENT_PO2; sample.event.type = SAMPLE_EVENT_PO2;
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
} }
// NDL & deco // NDL & deco
@ -323,8 +344,7 @@ atomics_cobalt_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
sample.deco.type = DC_DECO_NDL; sample.deco.type = DC_DECO_NDL;
sample.deco.time = ndl; sample.deco.time = ndl;
sample.deco.depth = 0.0; sample.deco.depth = 0.0;
sample.deco.tts = 0; if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
offset += SZ_SEGMENT; offset += SZ_SEGMENT;
} }

View File

@ -51,6 +51,7 @@
#include "context-private.h" #include "context-private.h"
#include "iostream-private.h" #include "iostream-private.h"
#include "iterator-private.h" #include "iterator-private.h"
#include "descriptor-private.h"
#include "platform.h" #include "platform.h"
#ifdef _WIN32 #ifdef _WIN32
@ -454,7 +455,7 @@ dc_bluetooth_iterator_next (dc_iterator_t *abstract, void *out)
INFO (abstract->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s", INFO (abstract->context, "Discover: address=" DC_ADDRESS_FORMAT ", name=%s",
address, name ? name : ""); address, name ? name : "");
if (!dc_descriptor_filter (iterator->descriptor, DC_TRANSPORT_BLUETOOTH, name)) { if (!dc_descriptor_filter (iterator->descriptor, DC_TRANSPORT_BLUETOOTH, name, NULL)) {
continue; continue;
} }

View File

@ -31,8 +31,6 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &citizen_aqualand_device_vtable) #define ISINSTANCE(device) dc_device_isinstance((device), &citizen_aqualand_device_vtable)
#define SZ_HEADER 32
typedef struct citizen_aqualand_device_t { typedef struct citizen_aqualand_device_t {
dc_device_t base; dc_device_t base;
dc_iostream_t *iostream; dc_iostream_t *iostream;
@ -202,12 +200,6 @@ citizen_aqualand_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
unsigned char *data = dc_buffer_get_data (buffer); unsigned char *data = dc_buffer_get_data (buffer);
unsigned int size = dc_buffer_get_size (buffer); unsigned int size = dc_buffer_get_size (buffer);
if (size < SZ_HEADER) {
ERROR (abstract->context, "Dive header is too small (%u).", size);
dc_buffer_free (buffer);
return DC_STATUS_DATAFORMAT;
}
if (callback && memcmp (data + 0x05, device->fingerprint, sizeof (device->fingerprint)) != 0) { if (callback && memcmp (data + 0x05, device->fingerprint, sizeof (device->fingerprint)) != 0) {
callback (data, size, data + 0x05, sizeof (device->fingerprint), userdata); callback (data, size, data + 0x05, sizeof (device->fingerprint), userdata);
} }

View File

@ -35,7 +35,7 @@ dc_status_t
citizen_aqualand_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); citizen_aqualand_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
citizen_aqualand_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size); citizen_aqualand_parser_create (dc_parser_t **parser, dc_context_t *context);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -36,6 +36,7 @@ typedef struct citizen_aqualand_parser_t {
dc_parser_t base; dc_parser_t base;
} citizen_aqualand_parser_t; } citizen_aqualand_parser_t;
static dc_status_t citizen_aqualand_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
static dc_status_t citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t citizen_aqualand_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t citizen_aqualand_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static dc_status_t citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -43,6 +44,7 @@ static dc_status_t citizen_aqualand_parser_samples_foreach (dc_parser_t *abstrac
static const dc_parser_vtable_t citizen_aqualand_parser_vtable = { static const dc_parser_vtable_t citizen_aqualand_parser_vtable = {
sizeof(citizen_aqualand_parser_t), sizeof(citizen_aqualand_parser_t),
DC_FAMILY_CITIZEN_AQUALAND, DC_FAMILY_CITIZEN_AQUALAND,
citizen_aqualand_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -54,7 +56,7 @@ static const dc_parser_vtable_t citizen_aqualand_parser_vtable = {
dc_status_t dc_status_t
citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size) citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context)
{ {
citizen_aqualand_parser_t *parser = NULL; citizen_aqualand_parser_t *parser = NULL;
@ -62,7 +64,7 @@ citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context, const
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (citizen_aqualand_parser_t *) dc_parser_allocate (context, &citizen_aqualand_parser_vtable, data, size); parser = (citizen_aqualand_parser_t *) dc_parser_allocate (context, &citizen_aqualand_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -74,6 +76,13 @@ citizen_aqualand_parser_create (dc_parser_t **out, dc_context_t *context, const
} }
static dc_status_t
citizen_aqualand_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
return DC_STATUS_SUCCESS;
}
static dc_status_t static dc_status_t
citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) citizen_aqualand_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -232,15 +241,15 @@ citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
// Time // Time
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth // Depth
if (metric) if (metric)
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
else else
sample.depth = depth * FEET; sample.depth = depth * FEET;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Temperature // Temperature
if (time % 300 == 0) { if (time % 300 == 0) {
@ -251,7 +260,7 @@ citizen_aqualand_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
sample.temperature = temperature / 10.0; sample.temperature = temperature / 10.0;
else else
sample.temperature = (temperature - 32.0) * (5.0 / 9.0); sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
} }
} }
} }

View File

@ -603,7 +603,7 @@ cochran_commander_profile_size(cochran_commander_device_t *device, cochran_data_
// Corrupt dive, guess the end address // Corrupt dive, guess the end address
sample_end_address = cochran_commander_guess_sample_end_address(device, data, dive_num); sample_end_address = cochran_commander_guess_sample_end_address(device, data, dive_num);
return ringbuffer_distance(sample_start_address, sample_end_address, DC_RINGBUFFER_EMPTY, device->layout->rb_profile_begin, device->layout->rb_profile_end); return ringbuffer_distance(sample_start_address, sample_end_address, 0, 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 ); last_start_address = base + array_uint32_le(data.config + layout->cf_last_log );
// Create the ringbuffer stream. // Create the ringbuffer stream.
status = dc_rbstream_new (&rbstream, abstract, 1, layout->rbstream_size, layout->rb_profile_begin, layout->rb_profile_end, last_start_address, DC_RBSTREAM_BACKWARD); status = dc_rbstream_new (&rbstream, abstract, 1, layout->rbstream_size, layout->rb_profile_begin, layout->rb_profile_end, last_start_address);
if (status != DC_STATUS_SUCCESS) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream."); ERROR (abstract->context, "Failed to create the ringbuffer stream.");
goto error; goto error;

View File

@ -35,7 +35,7 @@ dc_status_t
cochran_commander_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); cochran_commander_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
cochran_commander_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model); cochran_commander_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -99,6 +99,7 @@ typedef struct cochran_commander_parser_t {
unsigned int nevents; unsigned int nevents;
} cochran_commander_parser_t ; } cochran_commander_parser_t ;
static dc_status_t cochran_commander_parser_set_data (dc_parser_t *parser, const unsigned char *data, unsigned int size);
static dc_status_t cochran_commander_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime); static dc_status_t cochran_commander_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime);
static dc_status_t cochran_commander_parser_get_field (dc_parser_t *parser, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t cochran_commander_parser_get_field (dc_parser_t *parser, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t cochran_commander_parser_samples_foreach (dc_parser_t *parser, dc_sample_callback_t callback, void *userdata); static dc_status_t cochran_commander_parser_samples_foreach (dc_parser_t *parser, dc_sample_callback_t callback, void *userdata);
@ -106,6 +107,7 @@ static dc_status_t cochran_commander_parser_samples_foreach (dc_parser_t *parser
static const dc_parser_vtable_t cochran_commander_parser_vtable = { static const dc_parser_vtable_t cochran_commander_parser_vtable = {
sizeof(cochran_commander_parser_t), sizeof(cochran_commander_parser_t),
DC_FAMILY_COCHRAN_COMMANDER, DC_FAMILY_COCHRAN_COMMANDER,
cochran_commander_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -313,7 +315,7 @@ cochran_commander_handle_event (cochran_commander_parser_t *parser, unsigned cha
sample.event.time = 0; sample.event.time = 0;
sample.event.value = 0; sample.event.value = 0;
sample.event.flags = event->flag; sample.event.flags = event->flag;
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
} }
} }
@ -350,7 +352,7 @@ cochran_commander_backparse(cochran_commander_parser_t *parser, const unsigned c
dc_status_t dc_status_t
cochran_commander_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model) cochran_commander_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{ {
cochran_commander_parser_t *parser = NULL; cochran_commander_parser_t *parser = NULL;
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
@ -359,7 +361,7 @@ cochran_commander_parser_create (dc_parser_t **out, dc_context_t *context, const
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (cochran_commander_parser_t *) dc_parser_allocate (context, &cochran_commander_parser_vtable, data, size); parser = (cochran_commander_parser_t *) dc_parser_allocate (context, &cochran_commander_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -405,6 +407,13 @@ error_free:
} }
static dc_status_t
cochran_commander_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
return DC_STATUS_SUCCESS;
}
static dc_status_t static dc_status_t
cochran_commander_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) cochran_commander_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -505,7 +514,6 @@ cochran_commander_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
// Gas percentages are decimal and encoded as // Gas percentages are decimal and encoded as
// highbyte = integer portion // highbyte = integer portion
// lowbyte = decimal portion, divide by 256 to get decimal value // lowbyte = decimal portion, divide by 256 to get decimal value
gasmix->usage = DC_USAGE_NONE;
gasmix->oxygen = array_uint16_le (data + layout->oxygen + 2 * flags) / 256.0 / 100; gasmix->oxygen = array_uint16_le (data + layout->oxygen + 2 * flags) / 256.0 / 100;
if (layout->helium == UNSUPPORTED) { if (layout->helium == UNSUPPORTED) {
gasmix->helium = 0; gasmix->helium = 0;
@ -570,26 +578,26 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
unsigned int temp = samples[0]; // Half degrees F unsigned int temp = samples[0]; // Half degrees F
unsigned int depth = samples[1]; // Half feet unsigned int depth = samples[1]; // Half feet
last_sample_time = sample.time = time * 1000; last_sample_time = sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
sample.depth = (depth / 2.0) * FEET; sample.depth = (depth / 2.0) * FEET;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
sample.temperature = (temp / 2.0 - 32.0) / 1.8; sample.temperature = (temp / 2.0 - 32.0) / 1.8;
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
sample.gasmix = 0; sample.gasmix = 0;
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
while (offset < size) { while (offset < size) {
const unsigned char *s = samples + offset; const unsigned char *s = samples + offset;
sample.time = time * 1000; sample.time = time;
if (last_sample_time != sample.time) { if (last_sample_time != sample.time) {
// We haven't issued this time yet. // We haven't issued this time yet.
last_sample_time = sample.time; last_sample_time = sample.time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
} }
if (*s & 0x80) { if (*s & 0x80) {
@ -607,8 +615,7 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
sample.deco.type = DC_DECO_DECOSTOP; sample.deco.type = DC_DECO_DECOSTOP;
sample.deco.time = 60; // We don't know the duration sample.deco.time = 60; // We don't know the duration
sample.deco.depth = deco_ceiling * FEET; sample.deco.depth = deco_ceiling * FEET;
sample.deco.tts = 0; if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
break; break;
case 0xAD: // Increment ceiling (shallower) case 0xAD: // Increment ceiling (shallower)
deco_ceiling -= 10; // feet deco_ceiling -= 10; // feet
@ -616,8 +623,7 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
sample.deco.type = DC_DECO_DECOSTOP; sample.deco.type = DC_DECO_DECOSTOP;
sample.deco.depth = deco_ceiling * FEET; sample.deco.depth = deco_ceiling * FEET;
sample.deco.time = 60; // We don't know the duration sample.deco.time = 60; // We don't know the duration
sample.deco.tts = 0; if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
break; break;
default: default:
cochran_commander_handle_event(parser, s[0], callback, userdata); cochran_commander_handle_event(parser, s[0], callback, userdata);
@ -630,7 +636,7 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
else else
temp += (*s & 0x0f); temp += (*s & 0x0f);
sample.temperature = (temp / 2.0 - 32.0) / 1.8; sample.temperature = (temp / 2.0 - 32.0) / 1.8;
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
} }
offset++; offset++;
@ -644,7 +650,7 @@ cochran_commander_parser_samples_foreach_tm (dc_parser_t *abstract, dc_sample_ca
depth += s[0] & 0x3f; depth += s[0] & 0x3f;
sample.depth = (depth / 2.0) * FEET; sample.depth = (depth / 2.0) * FEET;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
offset++; offset++;
time += sample_interval; time += sample_interval;
@ -708,27 +714,27 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
start_depth = array_uint16_le (data + layout->start_depth) / 256.0; start_depth = array_uint16_le (data + layout->start_depth) / 256.0;
} }
last_sample_time = sample.time = time * 1000; last_sample_time = sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
sample.depth = start_depth * FEET; sample.depth = start_depth * FEET;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
sample.temperature = (data[layout->start_temp] - 32.0) / 1.8; sample.temperature = (data[layout->start_temp] - 32.0) / 1.8;
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
sample.gasmix = 0; sample.gasmix = 0;
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
unsigned int last_gasmix = sample.gasmix; unsigned int last_gasmix = sample.gasmix;
while (offset < size) { while (offset < size) {
const unsigned char *s = samples + offset; const unsigned char *s = samples + offset;
sample.time = time * 1000; sample.time = time;
if (last_sample_time != sample.time) { if (last_sample_time != sample.time) {
// We haven't issued this time yet. // We haven't issued this time yet.
last_sample_time = sample.time; last_sample_time = sample.time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
} }
// If corrupt_dive end before offset // If corrupt_dive end before offset
@ -768,8 +774,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
sample.deco.type = DC_DECO_DECOSTOP; sample.deco.type = DC_DECO_DECOSTOP;
sample.deco.time = (array_uint16_le(s + 3) + 1) * 60; sample.deco.time = (array_uint16_le(s + 3) + 1) * 60;
sample.deco.depth = deco_ceiling * FEET; sample.deco.depth = deco_ceiling * FEET;
sample.deco.tts = 0; if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
break; break;
case 0xAD: // Increment ceiling (shallower) case 0xAD: // Increment ceiling (shallower)
deco_ceiling -= 10; // feet deco_ceiling -= 10; // feet
@ -777,8 +782,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
sample.deco.type = DC_DECO_DECOSTOP; sample.deco.type = DC_DECO_DECOSTOP;
sample.deco.depth = deco_ceiling * FEET; sample.deco.depth = deco_ceiling * FEET;
sample.deco.time = (array_uint16_le(s + 3) + 1) * 60; sample.deco.time = (array_uint16_le(s + 3) + 1) * 60;
sample.deco.tts = 0; if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
break; break;
case 0xC0: // Switched to FO2 21% mode (surface) case 0xC0: // Switched to FO2 21% mode (surface)
// Event seen upon surfacing // Event seen upon surfacing
@ -787,14 +791,14 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
case 0xEF: // Switched to gas blend 2 case 0xEF: // Switched to gas blend 2
if (last_gasmix != 1) { if (last_gasmix != 1) {
sample.gasmix = 1; sample.gasmix = 1;
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
last_gasmix = sample.gasmix; last_gasmix = sample.gasmix;
} }
break; break;
case 0xF3: // Switched to gas blend 1 case 0xF3: // Switched to gas blend 1
if (last_gasmix != 0) { if (last_gasmix != 0) {
sample.gasmix = 0; sample.gasmix = 0;
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
last_gasmix = sample.gasmix; last_gasmix = sample.gasmix;
} }
break; break;
@ -814,7 +818,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
depth += (s[0] & 0x3f); depth += (s[0] & 0x3f);
sample.depth = (start_depth + depth / 4.0) * FEET; sample.depth = (start_depth + depth / 4.0) * FEET;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Ascent rate is logged in the 0th sample, temp in the 1st, repeat. // Ascent rate is logged in the 0th sample, temp in the 1st, repeat.
if (time % 2 == 0) { if (time % 2 == 0) {
@ -830,7 +834,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
double temperature = s[1] / 2.0 + 20.0; double temperature = s[1] / 2.0 + 20.0;
sample.temperature = (temperature - 32.0) / 1.8; sample.temperature = (temperature - 32.0) / 1.8;
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
} }
// Cochran EMC models store NDL and deco stop time // Cochran EMC models store NDL and deco stop time
@ -851,8 +855,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
sample.deco.type = DC_DECO_NDL; sample.deco.type = DC_DECO_NDL;
sample.deco.time = deco_time * 60; sample.deco.time = deco_time * 60;
sample.deco.depth = 0; sample.deco.depth = 0;
sample.deco.tts = 0; if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
} }
break; break;
case 23: case 23:
@ -862,8 +865,7 @@ cochran_commander_parser_samples_foreach_emc (dc_parser_t *abstract, dc_sample_c
sample.deco.type = DC_DECO_DECOSTOP; sample.deco.type = DC_DECO_DECOSTOP;
sample.deco.depth = deco_ceiling * FEET; sample.deco.depth = deco_ceiling * FEET;
sample.deco.time = deco_time * 60; sample.deco.time = deco_time * 60;
sample.deco.tts = 0; if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
} }
break; break;
} }

View File

@ -38,8 +38,6 @@
#define SZ_PACKET 0x80 #define SZ_PACKET 0x80
#define SZ_PAGE (SZ_PACKET / 4) #define SZ_PAGE (SZ_PACKET / 4)
#define SZ_HEADER 32
#define IQ700 0x05 #define IQ700 0x05
#define EDY 0x08 #define EDY 0x08
@ -432,7 +430,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
} }
// Get the number of logbook items. // Get the number of logbook items.
unsigned int count = ringbuffer_distance (first, last, DC_RINGBUFFER_EMPTY, layout->rb_logbook_begin, layout->rb_logbook_end) + 1; unsigned int count = ringbuffer_distance (first, last, 0, layout->rb_logbook_begin, layout->rb_logbook_end) + 1;
// Get the profile pointer. // Get the profile pointer.
unsigned int eop = array_uint_le (logbook + layout->config + 2, layout->rb_logbook_size) * SZ_PAGE + layout->rb_profile_begin; unsigned int eop = array_uint_le (logbook + layout->config + 2, layout->rb_logbook_size) * SZ_PAGE + layout->rb_profile_begin;
@ -457,7 +455,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
} }
// Get the profile length. // Get the profile length.
unsigned int length = ringbuffer_distance (current, previous, DC_RINGBUFFER_FULL, layout->rb_profile_begin, layout->rb_profile_end); unsigned int length = ringbuffer_distance (current, previous, 1, layout->rb_profile_begin, layout->rb_profile_end);
// Check for a ringbuffer overflow. // Check for a ringbuffer overflow.
if (total + length > layout->rb_profile_end - layout->rb_profile_begin) { if (total + length > layout->rb_profile_end - layout->rb_profile_begin) {
@ -481,7 +479,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
// Create the ringbuffer stream. // Create the ringbuffer stream.
dc_rbstream_t *rbstream = NULL; dc_rbstream_t *rbstream = NULL;
rc = dc_rbstream_new (&rbstream, abstract, SZ_PAGE, SZ_PACKET, layout->rb_profile_begin, layout->rb_profile_end, eop, DC_RBSTREAM_BACKWARD); rc = dc_rbstream_new (&rbstream, abstract, SZ_PAGE, SZ_PACKET, layout->rb_profile_begin, layout->rb_profile_end, eop);
if (rc != DC_STATUS_SUCCESS) { if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream."); ERROR (abstract->context, "Failed to create the ringbuffer stream.");
return rc; return rc;
@ -510,7 +508,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
} }
// Get the profile length. // Get the profile length.
unsigned int length = ringbuffer_distance (current, previous, DC_RINGBUFFER_FULL, layout->rb_profile_begin, layout->rb_profile_end); unsigned int length = ringbuffer_distance (current, previous, 1, layout->rb_profile_begin, layout->rb_profile_end);
// Move to the begin of the current dive. // Move to the begin of the current dive.
offset -= length; offset -= length;
@ -524,13 +522,6 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
return rc; return rc;
} }
if (length < SZ_HEADER) {
ERROR (abstract->context, "Dive header is too small (%u).", length);
dc_rbstream_free (rbstream);
free (buffer);
return DC_STATUS_DATAFORMAT;
}
unsigned char *p = buffer + offset; unsigned char *p = buffer + offset;
if (memcmp (p, device->fingerprint, sizeof (device->fingerprint)) == 0) if (memcmp (p, device->fingerprint, sizeof (device->fingerprint)) == 0)

View File

@ -35,7 +35,7 @@ dc_status_t
cressi_edy_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); cressi_edy_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
cressi_edy_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model); cressi_edy_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -31,8 +31,6 @@
#define IQ700 0x05 #define IQ700 0x05
#define EDY 0x08 #define EDY 0x08
#define SZ_HEADER 32
typedef struct cressi_edy_parser_t cressi_edy_parser_t; typedef struct cressi_edy_parser_t cressi_edy_parser_t;
struct cressi_edy_parser_t { struct cressi_edy_parser_t {
@ -40,6 +38,7 @@ struct cressi_edy_parser_t {
unsigned int model; unsigned int model;
}; };
static dc_status_t cressi_edy_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
static dc_status_t cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static dc_status_t cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -47,6 +46,7 @@ static dc_status_t cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_
static const dc_parser_vtable_t cressi_edy_parser_vtable = { static const dc_parser_vtable_t cressi_edy_parser_vtable = {
sizeof(cressi_edy_parser_t), sizeof(cressi_edy_parser_t),
DC_FAMILY_CRESSI_EDY, DC_FAMILY_CRESSI_EDY,
cressi_edy_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -73,7 +73,7 @@ cressi_edy_parser_count_gasmixes (const unsigned char *data)
} }
dc_status_t dc_status_t
cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model) cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{ {
cressi_edy_parser_t *parser = NULL; cressi_edy_parser_t *parser = NULL;
@ -81,7 +81,7 @@ cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, const unsign
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (cressi_edy_parser_t *) dc_parser_allocate (context, &cressi_edy_parser_vtable, data, size); parser = (cressi_edy_parser_t *) dc_parser_allocate (context, &cressi_edy_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -96,10 +96,17 @@ cressi_edy_parser_create (dc_parser_t **out, dc_context_t *context, const unsign
} }
static dc_status_t
cressi_edy_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
return DC_STATUS_SUCCESS;
}
static dc_status_t static dc_status_t
cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) cressi_edy_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
if (abstract->size < SZ_HEADER) if (abstract->size < 32)
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
const unsigned char *p = abstract->data; const unsigned char *p = abstract->data;
@ -123,7 +130,7 @@ cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
{ {
cressi_edy_parser_t *parser = (cressi_edy_parser_t *) abstract; cressi_edy_parser_t *parser = (cressi_edy_parser_t *) abstract;
if (abstract->size < SZ_HEADER) if (abstract->size < 32)
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
const unsigned char *p = abstract->data; const unsigned char *p = abstract->data;
@ -145,7 +152,6 @@ cressi_edy_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
*((unsigned int *) value) = cressi_edy_parser_count_gasmixes(p); *((unsigned int *) value) = cressi_edy_parser_count_gasmixes(p);
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = 0.0; gasmix->helium = 0.0;
gasmix->oxygen = bcd2dec (p[0x17 - flags]) / 100.0; gasmix->oxygen = bcd2dec (p[0x17 - flags]) / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -182,7 +188,7 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
unsigned int ngasmixes = cressi_edy_parser_count_gasmixes(data); unsigned int ngasmixes = cressi_edy_parser_count_gasmixes(data);
unsigned int gasmix = 0xFFFFFFFF; unsigned int gasmix = 0xFFFFFFFF;
unsigned int offset = SZ_HEADER; unsigned int offset = 32;
while (offset + 2 <= size) { while (offset + 2 <= size) {
dc_sample_value_t sample = {0}; dc_sample_value_t sample = {0};
@ -195,13 +201,13 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
// Time (seconds). // Time (seconds).
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/10 m). // Depth (1/10 m).
unsigned int depth = bcd2dec (data[offset + 0] & 0x0F) * 100 + bcd2dec (data[offset + 1]); unsigned int depth = bcd2dec (data[offset + 0] & 0x0F) * 100 + bcd2dec (data[offset + 1]);
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Current gasmix // Current gasmix
if (ngasmixes) { if (ngasmixes) {
@ -214,7 +220,7 @@ cressi_edy_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
} }
if (idx != gasmix) { if (idx != gasmix) {
sample.gasmix = idx; sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix = idx; gasmix = idx;
} }
} }

View File

@ -35,7 +35,7 @@ dc_status_t
cressi_goa_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); cressi_goa_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
cressi_goa_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model); cressi_goa_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -62,6 +62,7 @@ typedef struct cressi_goa_layout_t {
unsigned int temperature; unsigned int temperature;
} cressi_goa_layout_t; } 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_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static dc_status_t cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -69,6 +70,7 @@ static dc_status_t cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_
static const dc_parser_vtable_t cressi_goa_parser_vtable = { static const dc_parser_vtable_t cressi_goa_parser_vtable = {
sizeof(cressi_goa_parser_t), sizeof(cressi_goa_parser_t),
DC_FAMILY_CRESSI_GOA, DC_FAMILY_CRESSI_GOA,
cressi_goa_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -126,7 +128,7 @@ static const cressi_goa_layout_t layouts[] = {
}; };
dc_status_t dc_status_t
cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model) cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{ {
cressi_goa_parser_t *parser = NULL; cressi_goa_parser_t *parser = NULL;
@ -134,7 +136,7 @@ cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, const unsign
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (cressi_goa_parser_t *) dc_parser_allocate (context, &cressi_goa_parser_vtable, data, size); parser = (cressi_goa_parser_t *) dc_parser_allocate (context, &cressi_goa_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -147,6 +149,12 @@ cressi_goa_parser_create (dc_parser_t **out, dc_context_t *context, const unsign
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
} }
static dc_status_t
cressi_goa_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
return DC_STATUS_SUCCESS;
}
static dc_status_t static dc_status_t
cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) cressi_goa_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -242,7 +250,6 @@ cressi_goa_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
*((unsigned int *) value) = ngasmixes; *((unsigned int *) value) = ngasmixes;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = 0.0; gasmix->helium = 0.0;
gasmix->oxygen = data[layout->gasmix + 2 * flags + 1] / 100.0; gasmix->oxygen = data[layout->gasmix + 2 * flags + 1] / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -322,25 +329,25 @@ cressi_goa_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
if (complete) { if (complete) {
// Time (seconds). // Time (seconds).
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Temperature (1/10 °C). // Temperature (1/10 °C).
if (have_temperature) { if (have_temperature) {
sample.temperature = temperature / 10.0; sample.temperature = temperature / 10.0;
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
have_temperature = 0; have_temperature = 0;
} }
// Depth (1/10 m). // Depth (1/10 m).
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Gas change // Gas change
if (divemode == SCUBA || divemode == NITROX) { if (divemode == SCUBA || divemode == NITROX) {
if (gasmix != gasmix_previous) { if (gasmix != gasmix_previous) {
sample.gasmix = gasmix; sample.gasmix = gasmix;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix_previous = gasmix; gasmix_previous = gasmix;
} }
} }

View File

@ -41,7 +41,7 @@
#define RB_PROFILE_BEGIN 0x1438 #define RB_PROFILE_BEGIN 0x1438
#define RB_PROFILE_END SZ_MEMORY #define RB_PROFILE_END SZ_MEMORY
#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_EMPTY, RB_PROFILE_BEGIN, RB_PROFILE_END) #define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, 0, RB_PROFILE_BEGIN, RB_PROFILE_END)
#define MAXRETRIES 4 #define MAXRETRIES 4
#define PACKETSIZE 32 #define PACKETSIZE 32

View File

@ -35,7 +35,7 @@ dc_status_t
cressi_leonardo_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); cressi_leonardo_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
cressi_leonardo_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model); cressi_leonardo_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -39,6 +39,7 @@ struct cressi_leonardo_parser_t {
unsigned int model; unsigned int model;
}; };
static dc_status_t cressi_leonardo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
static dc_status_t cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t cressi_leonardo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t cressi_leonardo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static dc_status_t cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -46,6 +47,7 @@ static dc_status_t cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract
static const dc_parser_vtable_t cressi_leonardo_parser_vtable = { static const dc_parser_vtable_t cressi_leonardo_parser_vtable = {
sizeof(cressi_leonardo_parser_t), sizeof(cressi_leonardo_parser_t),
DC_FAMILY_CRESSI_LEONARDO, DC_FAMILY_CRESSI_LEONARDO,
cressi_leonardo_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -57,7 +59,7 @@ static const dc_parser_vtable_t cressi_leonardo_parser_vtable = {
dc_status_t dc_status_t
cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model) cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{ {
cressi_leonardo_parser_t *parser = NULL; cressi_leonardo_parser_t *parser = NULL;
@ -65,7 +67,7 @@ cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, const u
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (cressi_leonardo_parser_t *) dc_parser_allocate (context, &cressi_leonardo_parser_vtable, data, size); parser = (cressi_leonardo_parser_t *) dc_parser_allocate (context, &cressi_leonardo_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -79,6 +81,13 @@ cressi_leonardo_parser_create (dc_parser_t **out, dc_context_t *context, const u
} }
static dc_status_t
cressi_leonardo_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
return DC_STATUS_SUCCESS;
}
static dc_status_t static dc_status_t
cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) cressi_leonardo_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -137,7 +146,6 @@ cressi_leonardo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, u
} }
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = 0.0; gasmix->helium = 0.0;
gasmix->oxygen = data[0x19] / 100.0; gasmix->oxygen = data[0x19] / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -188,12 +196,12 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
// Time (seconds). // Time (seconds).
time += surftime; time += surftime;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/10 m). // Depth (1/10 m).
sample.depth = 0.0; sample.depth = 0.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
offset += 4; offset += 4;
} else { } else {
@ -203,17 +211,17 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
// Time (seconds). // Time (seconds).
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/10 m). // Depth (1/10 m).
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Gas change. // Gas change.
if (gasmix != gasmix_previous) { if (gasmix != gasmix_previous) {
sample.gasmix = gasmix; sample.gasmix = gasmix;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix_previous = gasmix; gasmix_previous = gasmix;
} }
@ -223,7 +231,7 @@ cressi_leonardo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
sample.event.time = 0; sample.event.time = 0;
sample.event.flags = 0; sample.event.flags = 0;
sample.event.value = ascent; sample.event.value = ascent;
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
} }
offset += 2; offset += 2;

View File

@ -36,7 +36,7 @@ dc_status_t
deepblu_cosmiq_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); deepblu_cosmiq_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
deepblu_cosmiq_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size); deepblu_cosmiq_parser_create (dc_parser_t **parser, dc_context_t *context);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -41,6 +41,7 @@ typedef struct deepblu_cosmiq_parser_t {
double hydrostatic; double hydrostatic;
} deepblu_cosmiq_parser_t; } 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_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_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t deepblu_cosmiq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t deepblu_cosmiq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
@ -49,6 +50,7 @@ static dc_status_t deepblu_cosmiq_parser_samples_foreach (dc_parser_t *abstract,
static const dc_parser_vtable_t deepblu_cosmiq_parser_vtable = { static const dc_parser_vtable_t deepblu_cosmiq_parser_vtable = {
sizeof(deepblu_cosmiq_parser_t), sizeof(deepblu_cosmiq_parser_t),
DC_FAMILY_DEEPBLU_COSMIQ, DC_FAMILY_DEEPBLU_COSMIQ,
deepblu_cosmiq_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
deepblu_cosmiq_parser_set_density, /* set_density */ deepblu_cosmiq_parser_set_density, /* set_density */
@ -59,7 +61,7 @@ static const dc_parser_vtable_t deepblu_cosmiq_parser_vtable = {
}; };
dc_status_t dc_status_t
deepblu_cosmiq_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size) deepblu_cosmiq_parser_create (dc_parser_t **out, dc_context_t *context)
{ {
deepblu_cosmiq_parser_t *parser = NULL; deepblu_cosmiq_parser_t *parser = NULL;
@ -67,7 +69,7 @@ deepblu_cosmiq_parser_create (dc_parser_t **out, dc_context_t *context, const un
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (deepblu_cosmiq_parser_t *) dc_parser_allocate (context, &deepblu_cosmiq_parser_vtable, data, size); parser = (deepblu_cosmiq_parser_t *) dc_parser_allocate (context, &deepblu_cosmiq_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -81,6 +83,12 @@ deepblu_cosmiq_parser_create (dc_parser_t **out, dc_context_t *context, const un
return DC_STATUS_SUCCESS; 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 static dc_status_t
deepblu_cosmiq_parser_set_density (dc_parser_t *abstract, double density) deepblu_cosmiq_parser_set_density (dc_parser_t *abstract, double density)
{ {
@ -143,7 +151,6 @@ deepblu_cosmiq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
*((unsigned int *) value) = mode == SCUBA; *((unsigned int *) value) = mode == SCUBA;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->oxygen = data[3] / 100.0; gasmix->oxygen = data[3] / 100.0;
gasmix->helium = 0.0; gasmix->helium = 0.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -197,14 +204,14 @@ deepblu_cosmiq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
offset += SZ_SAMPLE; offset += SZ_SAMPLE;
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
sample.depth = (signed int) (depth - atmospheric) * (BAR / 1000.0) / parser->hydrostatic; sample.depth = (signed int) (depth - atmospheric) * (BAR / 1000.0) / parser->hydrostatic;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
sample.temperature = temperature / 10.0; sample.temperature = temperature / 10.0;
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
} }
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;

View File

@ -35,7 +35,7 @@ dc_status_t
deepsix_excursion_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream); deepsix_excursion_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
deepsix_excursion_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size); deepsix_excursion_parser_create (dc_parser_t **parser, dc_context_t *context);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -112,6 +112,7 @@ typedef struct deepsix_excursion_parser_t {
deepsix_excursion_gasmix_t gasmix[MAX_GASMIXES]; deepsix_excursion_gasmix_t gasmix[MAX_GASMIXES];
} deepsix_excursion_parser_t; } 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_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_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t deepsix_excursion_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static dc_status_t deepsix_excursion_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -121,6 +122,7 @@ static dc_status_t deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abs
static const dc_parser_vtable_t deepsix_parser_vtable = { static const dc_parser_vtable_t deepsix_parser_vtable = {
sizeof(deepsix_excursion_parser_t), sizeof(deepsix_excursion_parser_t),
DC_FAMILY_DEEPSIX_EXCURSION, DC_FAMILY_DEEPSIX_EXCURSION,
deepsix_excursion_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -183,7 +185,7 @@ deepsix_excursion_find_gasmix(deepsix_excursion_parser_t *parser, unsigned int o
} }
dc_status_t dc_status_t
deepsix_excursion_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size) deepsix_excursion_parser_create (dc_parser_t **out, dc_context_t *context)
{ {
deepsix_excursion_parser_t *parser = NULL; deepsix_excursion_parser_t *parser = NULL;
@ -191,7 +193,7 @@ deepsix_excursion_parser_create (dc_parser_t **out, dc_context_t *context, const
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (deepsix_excursion_parser_t *) dc_parser_allocate (context, &deepsix_parser_vtable, data, size); parser = (deepsix_excursion_parser_t *) dc_parser_allocate (context, &deepsix_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -211,6 +213,23 @@ deepsix_excursion_parser_create (dc_parser_t **out, dc_context_t *context, const
return DC_STATUS_SUCCESS; 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 static dc_status_t
deepsix_excursion_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) deepsix_excursion_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -303,7 +322,6 @@ deepsix_excursion_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
*((unsigned int *) value) = parser->ngasmixes; *((unsigned int *) value) = parser->ngasmixes;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0; gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
gasmix->helium = parser->gasmix[flags].helium / 100.0; gasmix->helium = parser->gasmix[flags].helium / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -405,11 +423,11 @@ deepsix_excursion_parser_samples_foreach_v0 (dc_parser_t *abstract, dc_sample_ca
if (type == TEMPERATURE) { if (type == TEMPERATURE) {
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback(DC_SAMPLE_TIME, &sample, userdata); if (callback) callback(DC_SAMPLE_TIME, sample, userdata);
sample.depth = pressure_to_depth(depth, atmospheric, DENSITY); 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) { if (type == ALARM) {
@ -422,11 +440,11 @@ deepsix_excursion_parser_samples_foreach_v0 (dc_parser_t *abstract, dc_sample_ca
length = 8; length = 8;
} else if (temperature >= 10) { } else if (temperature >= 10) {
sample.temperature = temperature / 10.0; sample.temperature = temperature / 10.0;
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback(DC_SAMPLE_TEMPERATURE, sample, userdata);
} }
} else { } else {
sample.temperature = temperature / 10.0; sample.temperature = temperature / 10.0;
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback(DC_SAMPLE_TEMPERATURE, sample, userdata);
} }
} else if (type == DECO) { } else if (type == DECO) {
unsigned int deco = array_uint16_le(data + offset + 4); unsigned int deco = array_uint16_le(data + offset + 4);
@ -436,7 +454,7 @@ deepsix_excursion_parser_samples_foreach_v0 (dc_parser_t *abstract, dc_sample_ca
} else if (type == CNS) { } else if (type == CNS) {
unsigned int cns = array_uint16_le(data + offset + 4); unsigned int cns = array_uint16_le(data + offset + 4);
sample.cns = cns / 100.0; sample.cns = cns / 100.0;
if (callback) callback(DC_SAMPLE_CNS, &sample, userdata); if (callback) callback(DC_SAMPLE_CNS, sample, userdata);
} }
offset += length; offset += length;
@ -573,12 +591,12 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca
// Time (seconds). // Time (seconds).
time += samplerate; time += samplerate;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
unsigned int depth = array_uint16_le (data + offset); unsigned int depth = array_uint16_le (data + offset);
sample.depth = pressure_to_depth(depth, atmospheric, density); 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; offset += 2;
// event info // event info
@ -646,7 +664,7 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca
break; break;
} }
if (sample.event.type != SAMPLE_EVENT_NONE) { if (sample.event.type != SAMPLE_EVENT_NONE) {
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
} }
} }
break; break;
@ -668,7 +686,7 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca
} }
sample.gasmix = mix_idx; sample.gasmix = mix_idx;
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
break; break;
case EVENT_SAMPLES_MISSED: case EVENT_SAMPLES_MISSED:
count = array_uint16_le(data + offset + event_offset); count = array_uint16_le(data + offset + event_offset);
@ -709,12 +727,12 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca
case SAMPLE_TEMPERATURE: case SAMPLE_TEMPERATURE:
value = array_uint16_le(data + offset); value = array_uint16_le(data + offset);
sample.temperature = value / 10.0; sample.temperature = value / 10.0;
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback(DC_SAMPLE_TEMPERATURE, sample, userdata);
break; break;
case SAMPLE_CNS: case SAMPLE_CNS:
value = array_uint16_le(data + offset); value = array_uint16_le(data + offset);
sample.cns = value / 10000.0; sample.cns = value / 10000.0;
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata); if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
break; break;
case SAMPLE_DECO_NDL: case SAMPLE_DECO_NDL:
deco_flags = data[offset]; deco_flags = data[offset];
@ -734,7 +752,7 @@ deepsix_excursion_parser_samples_foreach_v1 (dc_parser_t *abstract, dc_sample_ca
sample.deco.depth = 0; sample.deco.depth = 0;
sample.deco.time = deco_ndl_tts; sample.deco.time = deco_ndl_tts;
} }
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata); if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
break; break;
default: default:
break; break;

View File

@ -1,7 +1,7 @@
/* /*
* libdivecomputer * libdivecomputer
* *
* Copyright (C) 2023 Janice McLaughlin * Copyright (C) 2017 Jef Driesen
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -19,22 +19,30 @@
* MA 02110-1301 USA * MA 02110-1301 USA
*/ */
#ifndef PELAGIC_I330R_H #ifndef DC_DESCRIPTOR_PRIVATE_H
#define PELAGIC_I330R_H #define DC_DESCRIPTOR_PRIVATE_H
#include <libdivecomputer/context.h> #include <libdivecomputer/descriptor.h>
#include <libdivecomputer/iostream.h>
#include <libdivecomputer/device.h>
#include <libdivecomputer/parser.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
dc_status_t typedef struct dc_usb_desc_t {
pelagic_i330r_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model); 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);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif /* PELAGIC_I330R_H */ #endif /* DC_DESCRIPTOR_PRIVATE_H */

View File

@ -23,10 +23,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <libdivecomputer/descriptor.h> #include "descriptor-private.h"
#include <libdivecomputer/usbhid.h>
#include <libdivecomputer/usb.h>
#include "iterator-private.h" #include "iterator-private.h"
#include "platform.h" #include "platform.h"
@ -39,26 +36,36 @@
values, \ values, \
C_ARRAY_SIZE(values) - isnullterminated, \ C_ARRAY_SIZE(values) - isnullterminated, \
C_ARRAY_ITEMSIZE(values), \ C_ARRAY_ITEMSIZE(values), \
match) match, \
NULL, NULL, 0)
#define DC_FILTER_INTERNAL_WITH_PARAMS(key, values, isnullterminated, match, params_dst, params_src) \
dc_filter_internal( \
key, \
values, \
C_ARRAY_SIZE(values) - isnullterminated, \
C_ARRAY_ITEMSIZE(values), \
match, \
params_dst, params_src, sizeof *(params_src))
typedef int (*dc_match_t)(const void *, const void *); typedef int (*dc_match_t)(const void *, const void *);
typedef int (*dc_filter_t) (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); typedef int (*dc_filter_t) (dc_transport_t transport, const void *userdata, void *params);
static int dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, void *params);
static int dc_filter_suunto (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); static int dc_filter_suunto (dc_transport_t transport, const void *userdata, void *params);
static int dc_filter_shearwater (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); static int dc_filter_shearwater (dc_transport_t transport, const void *userdata, void *params);
static int dc_filter_hw (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); static int dc_filter_hw (dc_transport_t transport, const void *userdata, void *params);
static int dc_filter_tecdiving (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata, void *params);
static int dc_filter_mares (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); static int dc_filter_mares (dc_transport_t transport, const void *userdata, void *params);
static int dc_filter_divesystem (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); static int dc_filter_divesystem (dc_transport_t transport, const void *userdata, void *params);
static int dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, void *params);
static int dc_filter_mclean (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); static int dc_filter_mclean (dc_transport_t transport, const void *userdata, void *params);
static int dc_filter_atomic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); static int dc_filter_atomic (dc_transport_t transport, const void *userdata, void *params);
static int dc_filter_deepsix (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata); static int dc_filter_deepsix (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 int dc_filter_deepblu (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 int dc_filter_oceans (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 int dc_filter_divesoft (dc_transport_t transport, const void *userdata, void *params);
static dc_status_t dc_descriptor_iterator_next (dc_iterator_t *iterator, void *item); static dc_status_t dc_descriptor_iterator_next (dc_iterator_t *iterator, void *item);
@ -170,10 +177,7 @@ 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 TEK", DC_FAMILY_UWATEC_SMART, 0x31, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
{"Scubapro", "G2", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec}, {"Scubapro", "G2", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
{"Scubapro", "G2 Console", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec}, {"Scubapro", "G2 Console", DC_FAMILY_UWATEC_SMART, 0x32, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
{"Scubapro", "G3", DC_FAMILY_UWATEC_SMART, 0x34, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
{"Scubapro", "G2 HUD", DC_FAMILY_UWATEC_SMART, 0x42, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec}, {"Scubapro", "G2 HUD", DC_FAMILY_UWATEC_SMART, 0x42, DC_TRANSPORT_USBHID | DC_TRANSPORT_BLE, dc_filter_uwatec},
{"Scubapro", "Luna 2.0 AI", DC_FAMILY_UWATEC_SMART, 0x50, DC_TRANSPORT_BLE, dc_filter_uwatec},
{"Scubapro", "Luna 2.0", DC_FAMILY_UWATEC_SMART, 0x51, DC_TRANSPORT_BLE, dc_filter_uwatec},
/* Reefnet */ /* Reefnet */
{"Reefnet", "Sensus", DC_FAMILY_REEFNET_SENSUS, 1, DC_TRANSPORT_SERIAL, NULL}, {"Reefnet", "Sensus", DC_FAMILY_REEFNET_SENSUS, 1, DC_TRANSPORT_SERIAL, NULL},
{"Reefnet", "Sensus Pro", DC_FAMILY_REEFNET_SENSUSPRO, 2, DC_TRANSPORT_SERIAL, NULL}, {"Reefnet", "Sensus Pro", DC_FAMILY_REEFNET_SENSUSPRO, 2, DC_TRANSPORT_SERIAL, NULL},
@ -272,9 +276,6 @@ static const dc_descriptor_t g_descriptors[] = {
{"Aqualung", "i470TC", DC_FAMILY_OCEANIC_ATOM2, 0x4743, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic}, {"Aqualung", "i470TC", DC_FAMILY_OCEANIC_ATOM2, 0x4743, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
{"Aqualung", "i200C", DC_FAMILY_OCEANIC_ATOM2, 0x4749, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic}, {"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}, {"Oceanic", "Geo Air", DC_FAMILY_OCEANIC_ATOM2, 0x474B, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
/* Pelagic I330R */
{"Apeks", "DSX", DC_FAMILY_PELAGIC_I330R, 0x4741, DC_TRANSPORT_BLE, dc_filter_oceanic},
{"Aqualung", "i330R", DC_FAMILY_PELAGIC_I330R, 0x4744, DC_TRANSPORT_BLE, dc_filter_oceanic},
/* Mares Nemo */ /* Mares Nemo */
{"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL}, {"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
{"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL}, {"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
@ -307,10 +308,6 @@ static const dc_descriptor_t g_descriptors[] = {
{"Mares", "Smart Air", DC_FAMILY_MARES_ICONHD , 0x24, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares}, {"Mares", "Smart Air", DC_FAMILY_MARES_ICONHD , 0x24, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
{"Mares", "Quad", DC_FAMILY_MARES_ICONHD , 0x29, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares}, {"Mares", "Quad", DC_FAMILY_MARES_ICONHD , 0x29, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_mares},
{"Mares", "Horizon", DC_FAMILY_MARES_ICONHD , 0x2C, DC_TRANSPORT_SERIAL, NULL}, {"Mares", "Horizon", DC_FAMILY_MARES_ICONHD , 0x2C, DC_TRANSPORT_SERIAL, NULL},
{"Mares", "Puck Air 2", DC_FAMILY_MARES_ICONHD , 0x2D, DC_TRANSPORT_BLE, dc_filter_mares},
{"Mares", "Sirius", DC_FAMILY_MARES_ICONHD , 0x2F, DC_TRANSPORT_BLE, dc_filter_mares},
{"Mares", "Quad Ci", DC_FAMILY_MARES_ICONHD , 0x31, DC_TRANSPORT_BLE, dc_filter_mares},
{"Mares", "Puck 4", DC_FAMILY_MARES_ICONHD , 0x35, DC_TRANSPORT_BLE, dc_filter_mares},
/* Heinrichs Weikamp */ /* Heinrichs Weikamp */
{"Heinrichs Weikamp", "OSTC", DC_FAMILY_HW_OSTC, 0, DC_TRANSPORT_SERIAL, NULL}, {"Heinrichs Weikamp", "OSTC", DC_FAMILY_HW_OSTC, 0, DC_TRANSPORT_SERIAL, NULL},
{"Heinrichs Weikamp", "OSTC Mk2", DC_FAMILY_HW_OSTC, 1, DC_TRANSPORT_SERIAL, NULL}, {"Heinrichs Weikamp", "OSTC Mk2", DC_FAMILY_HW_OSTC, 1, DC_TRANSPORT_SERIAL, NULL},
@ -364,7 +361,6 @@ static const dc_descriptor_t g_descriptors[] = {
{"Shearwater", "Peregrine", DC_FAMILY_SHEARWATER_PETREL, 9, DC_TRANSPORT_BLE, dc_filter_shearwater}, {"Shearwater", "Peregrine", DC_FAMILY_SHEARWATER_PETREL, 9, DC_TRANSPORT_BLE, dc_filter_shearwater},
{"Shearwater", "Petrel 3", DC_FAMILY_SHEARWATER_PETREL, 10, DC_TRANSPORT_BLE, dc_filter_shearwater}, {"Shearwater", "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", "Perdix 2", DC_FAMILY_SHEARWATER_PETREL, 11, DC_TRANSPORT_BLE, dc_filter_shearwater},
{"Shearwater", "Tern", DC_FAMILY_SHEARWATER_PETREL, 12, DC_TRANSPORT_BLE, dc_filter_shearwater},
/* Dive Rite NiTek Q */ /* Dive Rite NiTek Q */
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0, DC_TRANSPORT_SERIAL, NULL}, {"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0, DC_TRANSPORT_SERIAL, NULL},
/* Citizen Hyper Aqualand */ /* Citizen Hyper Aqualand */
@ -418,20 +414,6 @@ static const dc_descriptor_t g_descriptors[] = {
{"Ratio", "iX3M 2021 Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x73, DC_TRANSPORT_SERIAL, NULL}, {"Ratio", "iX3M 2021 Pro Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x73, DC_TRANSPORT_SERIAL, NULL},
{"Ratio", "iX3M 2021 Pro Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x74, DC_TRANSPORT_SERIAL, NULL}, {"Ratio", "iX3M 2021 Pro Tech+", DC_FAMILY_DIVESYSTEM_IDIVE, 0x74, DC_TRANSPORT_SERIAL, NULL},
{"Ratio", "iX3M 2021 Pro Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x75, DC_TRANSPORT_SERIAL, NULL}, {"Ratio", "iX3M 2021 Pro Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x75, DC_TRANSPORT_SERIAL, NULL},
{"Ratio", "iDive 2 Free", DC_FAMILY_DIVESYSTEM_IDIVE, 0x80, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
{"Ratio", "iDive 2 Fancy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x81, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
{"Ratio", "iDive 2 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x82, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
{"Ratio", "iDive 2 Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x83, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
{"Ratio", "iDive 2 Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x84, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
{"Ratio", "iDive 2 Tech", DC_FAMILY_DIVESYSTEM_IDIVE, 0x85, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
{"Ratio", "iDive 2 Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x86, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
{"Ratio", "iX3M 2 GPS Gauge", DC_FAMILY_DIVESYSTEM_IDIVE, 0x90, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
{"Ratio", "iX3M 2 GPS Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x91, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
{"Ratio", "iX3M 2 GPS Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x92, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
{"Ratio", "iX3M 2 GPS Deep", DC_FAMILY_DIVESYSTEM_IDIVE, 0x93, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
{"Ratio", "iX3M 2 GPS Tech", DC_FAMILY_DIVESYSTEM_IDIVE, 0x94, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
{"Ratio", "iX3M 2 GPS Reb", DC_FAMILY_DIVESYSTEM_IDIVE, 0x95, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
{"Ratio", "ATOM", DC_FAMILY_DIVESYSTEM_IDIVE, 0x96, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
{"Ratio", "iX3M 2 Gauge", DC_FAMILY_DIVESYSTEM_IDIVE, 0x100, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem}, {"Ratio", "iX3M 2 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 Easy", DC_FAMILY_DIVESYSTEM_IDIVE, 0x101, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
{"Ratio", "iX3M 2 Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x102, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem}, {"Ratio", "iX3M 2 Pro", DC_FAMILY_DIVESYSTEM_IDIVE, 0x102, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_divesystem},
@ -461,6 +443,7 @@ static const dc_descriptor_t g_descriptors[] = {
{"Deep Six", "Excursion", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix}, {"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}, {"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}, {"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}, {"Scorpena", "Alpha", DC_FAMILY_DEEPSIX_EXCURSION, 0, DC_TRANSPORT_BLE, dc_filter_deepsix},
/* Seac Screen */ /* Seac Screen */
{"Seac", "Screen", DC_FAMILY_SEAC_SCREEN, 0, DC_TRANSPORT_SERIAL, NULL}, {"Seac", "Screen", DC_FAMILY_SEAC_SCREEN, 0, DC_TRANSPORT_SERIAL, NULL},
@ -510,15 +493,6 @@ dc_match_usb (const void *key, const void *value)
return k->vid == v->vid && k->pid == v->pid; return k->vid == v->vid && k->pid == v->pid;
} }
static int
dc_match_usbhid (const void *key, const void *value)
{
const dc_usbhid_desc_t *k = (const dc_usbhid_desc_t *) key;
const dc_usbhid_desc_t *v = (const dc_usbhid_desc_t *) value;
return k->vid == v->vid && k->pid == v->pid;
}
static int static int
dc_match_number_with_prefix (const void *key, const void *value) dc_match_number_with_prefix (const void *key, const void *value)
{ {
@ -559,13 +533,16 @@ dc_match_oceanic (const void *key, const void *value)
} }
static int static int
dc_filter_internal (const void *key, const void *values, size_t count, size_t size, dc_match_t match) dc_filter_internal (const void *key, const void *values, size_t count, size_t size, dc_match_t match, void *params_dst, const void *params_src, size_t params_size)
{ {
if (key == NULL) if (key == NULL)
return 1; return 1;
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
if (match (key, (const unsigned char *) values + i * size)) { if (match (key, (const unsigned char *) values + i * size)) {
if (params_src && params_dst) {
memcpy (params_dst, params_src, params_size);
}
return 1; return 1;
} }
} }
@ -580,8 +557,7 @@ static const char * const rfcomm[] = {
NULL NULL
}; };
static int static int dc_filter_uwatec (dc_transport_t transport, const void *userdata, void *params)
dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const irda[] = { static const char * const irda[] = {
"Aladin Smart Com", "Aladin Smart Com",
@ -592,7 +568,7 @@ dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const v
"UWATEC Galileo", "UWATEC Galileo",
"UWATEC Galileo Sol", "UWATEC Galileo Sol",
}; };
static const dc_usbhid_desc_t usbhid[] = { static const dc_usb_desc_t usbhid[] = {
{0x2e6c, 0x3201}, // G2, G2 TEK {0x2e6c, 0x3201}, // G2, G2 TEK
{0x2e6c, 0x3211}, // G2 Console {0x2e6c, 0x3211}, // G2 Console
{0x2e6c, 0x4201}, // G2 HUD {0x2e6c, 0x4201}, // G2 HUD
@ -605,15 +581,12 @@ dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const v
"A1", "A1",
"A2", "A2",
"G2 TEK", "G2 TEK",
"Galileo 3",
"Luna 2.0 AI",
"Luna 2.0",
}; };
if (transport == DC_TRANSPORT_IRDA) { if (transport == DC_TRANSPORT_IRDA) {
return DC_FILTER_INTERNAL (userdata, irda, 0, dc_match_name); return DC_FILTER_INTERNAL (userdata, irda, 0, dc_match_name);
} else if (transport == DC_TRANSPORT_USBHID) { } else if (transport == DC_TRANSPORT_USBHID) {
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usbhid); return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usb);
} else if (transport == DC_TRANSPORT_BLE) { } else if (transport == DC_TRANSPORT_BLE) {
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name); return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name);
} }
@ -621,10 +594,9 @@ dc_filter_uwatec (dc_descriptor_t *descriptor, dc_transport_t transport, const v
return 1; return 1;
} }
static int static int dc_filter_suunto (dc_transport_t transport, const void *userdata, void *params)
dc_filter_suunto (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const dc_usbhid_desc_t usbhid[] = { static const dc_usb_desc_t usbhid[] = {
{0x1493, 0x0030}, // Eon Steel {0x1493, 0x0030}, // Eon Steel
{0x1493, 0x0033}, // Eon Core {0x1493, 0x0033}, // Eon Core
{0x1493, 0x0035}, // D5 {0x1493, 0x0035}, // D5
@ -638,7 +610,7 @@ dc_filter_suunto (dc_descriptor_t *descriptor, dc_transport_t transport, const v
}; };
if (transport == DC_TRANSPORT_USBHID) { if (transport == DC_TRANSPORT_USBHID) {
return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usbhid); return DC_FILTER_INTERNAL (userdata, usbhid, 0, dc_match_usb);
} else if (transport == DC_TRANSPORT_BLE) { } else if (transport == DC_TRANSPORT_BLE) {
return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix); return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix);
} }
@ -646,8 +618,7 @@ dc_filter_suunto (dc_descriptor_t *descriptor, dc_transport_t transport, const v
return 1; return 1;
} }
static int static int dc_filter_hw (dc_transport_t transport, const void *userdata, void *params)
dc_filter_hw (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"OSTC", "OSTC",
@ -663,8 +634,7 @@ dc_filter_hw (dc_descriptor_t *descriptor, dc_transport_t transport, const void
return 1; return 1;
} }
static int static int dc_filter_shearwater (dc_transport_t transport, const void *userdata, void *params)
dc_filter_shearwater (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"Predator", "Predator",
@ -676,7 +646,6 @@ dc_filter_shearwater (dc_descriptor_t *descriptor, dc_transport_t transport, con
"Perdix 2", "Perdix 2",
"Teric", "Teric",
"Peregrine", "Peregrine",
"Tern"
}; };
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) { if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
@ -688,8 +657,7 @@ dc_filter_shearwater (dc_descriptor_t *descriptor, dc_transport_t transport, con
return 1; return 1;
} }
static int static int dc_filter_tecdiving (dc_transport_t transport, const void *userdata, void *params)
dc_filter_tecdiving (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"DiveComputer", "DiveComputer",
@ -704,15 +672,11 @@ dc_filter_tecdiving (dc_descriptor_t *descriptor, dc_transport_t transport, cons
return 1; return 1;
} }
static int static int dc_filter_mares (dc_transport_t transport, const void *userdata, void *params)
dc_filter_mares (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"Mares bluelink pro", "Mares bluelink pro",
"Mares Genius", "Mares Genius",
"Sirius",
"Quad Ci",
"Puck4",
}; };
if (transport == DC_TRANSPORT_BLE) { if (transport == DC_TRANSPORT_BLE) {
@ -722,13 +686,11 @@ dc_filter_mares (dc_descriptor_t *descriptor, dc_transport_t transport, const vo
return 1; return 1;
} }
static int static int dc_filter_divesystem (dc_transport_t transport, const void *userdata, void *params)
dc_filter_divesystem (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"DS", "DS",
"IX5M", "IX5M",
"RATIO-",
}; };
if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) { if (transport == DC_TRANSPORT_BLUETOOTH || transport == DC_TRANSPORT_BLE) {
@ -738,8 +700,7 @@ dc_filter_divesystem (dc_descriptor_t *descriptor, dc_transport_t transport, con
return 1; return 1;
} }
static int static int dc_filter_oceanic (dc_transport_t transport, const void *userdata, void *params)
dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const unsigned int model[] = { static const unsigned int model[] = {
0x4552, // Oceanic Pro Plus X 0x4552, // Oceanic Pro Plus X
@ -753,10 +714,8 @@ dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const
0x4654, // Oceanic Veo 4.0 0x4654, // Oceanic Veo 4.0
0x4655, // Sherwood Wisdom 4 0x4655, // Sherwood Wisdom 4
0x4656, // Oceanic Pro Plus 4 0x4656, // Oceanic Pro Plus 4
0x4741, // Apeks DSX
0x4742, // Sherwood Beacon 0x4742, // Sherwood Beacon
0x4743, // Aqualung i470TC 0x4743, // Aqualung i470TC
0x4744, // Aqualung i330R
0x4749, // Aqualung i200C 0x4749, // Aqualung i200C
0x474B, // Oceanic Geo Air 0x474B, // Oceanic Geo Air
}; };
@ -768,8 +727,7 @@ dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const
return 1; return 1;
} }
static int static int dc_filter_mclean(dc_transport_t transport, const void *userdata, void *params)
dc_filter_mclean(dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"McLean Extreme", "McLean Extreme",
@ -784,27 +742,30 @@ dc_filter_mclean(dc_descriptor_t *descriptor, dc_transport_t transport, const vo
return 1; return 1;
} }
static int static int dc_filter_atomic (dc_transport_t transport, const void *userdata, void *params)
dc_filter_atomic (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const dc_usb_desc_t usb[] = { static const dc_usb_desc_t usb[] = {
{0x0471, 0x0888}, // Atomic Aquatics Cobalt {0x0471, 0x0888}, // Atomic Aquatics Cobalt
}; };
static const dc_usb_params_t usb_params = {
0, 0x82, 0x02
};
if (transport == DC_TRANSPORT_USB) { if (transport == DC_TRANSPORT_USB) {
return DC_FILTER_INTERNAL (userdata, usb, 0, dc_match_usb); return DC_FILTER_INTERNAL_WITH_PARAMS (userdata, usb, 0, dc_match_usb, params, &usb_params);
} }
return 1; return 1;
} }
static int static int dc_filter_deepsix (dc_transport_t transport, const void *userdata, void *params)
dc_filter_deepsix (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"EXCURSION", "EXCURSION",
"Crest-CR4", "Crest-CR4",
"CENTAURI", "CENTAURI",
"TC1",
"ALPHA", "ALPHA",
}; };
@ -815,8 +776,7 @@ dc_filter_deepsix (dc_descriptor_t *descriptor, dc_transport_t transport, const
return 1; return 1;
} }
static int static int dc_filter_deepblu (dc_transport_t transport, const void *userdata, void *params)
dc_filter_deepblu (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"COSMIQ", "COSMIQ",
@ -829,8 +789,7 @@ dc_filter_deepblu (dc_descriptor_t *descriptor, dc_transport_t transport, const
return 1; return 1;
} }
static int static int dc_filter_oceans (dc_transport_t transport, const void *userdata, void *params)
dc_filter_oceans (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"S1", "S1",
@ -843,8 +802,7 @@ dc_filter_oceans (dc_descriptor_t *descriptor, dc_transport_t transport, const v
return 1; return 1;
} }
static int static int dc_filter_divesoft (dc_transport_t transport, const void *userdata, void *params)
dc_filter_divesoft (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata)
{ {
static const char * const bluetooth[] = { static const char * const bluetooth[] = {
"Freedom", "Freedom",
@ -950,10 +908,10 @@ dc_descriptor_get_transports (dc_descriptor_t *descriptor)
} }
int int
dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata) dc_descriptor_filter (dc_descriptor_t *descriptor, dc_transport_t transport, const void *userdata, void *params)
{ {
if (descriptor == NULL || descriptor->filter == NULL || userdata == NULL) if (descriptor == NULL || descriptor->filter == NULL || userdata == NULL)
return 1; return 1;
return descriptor->filter (descriptor, transport, userdata); return descriptor->filter (transport, userdata, params);
} }

View File

@ -38,7 +38,6 @@
#include "oceanic_atom2.h" #include "oceanic_atom2.h"
#include "oceanic_veo250.h" #include "oceanic_veo250.h"
#include "oceanic_vtpro.h" #include "oceanic_vtpro.h"
#include "pelagic_i330r.h"
#include "mares_darwin.h" #include "mares_darwin.h"
#include "mares_iconhd.h" #include "mares_iconhd.h"
#include "mares_nemo.h" #include "mares_nemo.h"
@ -163,9 +162,6 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
case DC_FAMILY_OCEANIC_ATOM2: case DC_FAMILY_OCEANIC_ATOM2:
rc = oceanic_atom2_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor)); rc = oceanic_atom2_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
break; break;
case DC_FAMILY_PELAGIC_I330R:
rc = pelagic_i330r_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
break;
case DC_FAMILY_MARES_NEMO: case DC_FAMILY_MARES_NEMO:
rc = mares_nemo_device_open (&device, context, iostream); rc = mares_nemo_device_open (&device, context, iostream);
break; break;
@ -176,7 +172,7 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
rc = mares_darwin_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor)); rc = mares_darwin_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
break; break;
case DC_FAMILY_MARES_ICONHD: case DC_FAMILY_MARES_ICONHD:
rc = mares_iconhd_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor)); rc = mares_iconhd_device_open (&device, context, iostream);
break; break;
case DC_FAMILY_HW_OSTC: case DC_FAMILY_HW_OSTC:
rc = hw_ostc_device_open (&device, context, iostream); rc = hw_ostc_device_open (&device, context, iostream);

View File

@ -35,7 +35,7 @@ dc_status_t
diverite_nitekq_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); diverite_nitekq_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
diverite_nitekq_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size); diverite_nitekq_parser_create (dc_parser_t **parser, dc_context_t *context);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -49,6 +49,7 @@ struct diverite_nitekq_parser_t {
double maxdepth; double maxdepth;
}; };
static dc_status_t diverite_nitekq_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
static dc_status_t diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t diverite_nitekq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t diverite_nitekq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static dc_status_t diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -56,6 +57,7 @@ static dc_status_t diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract
static const dc_parser_vtable_t diverite_nitekq_parser_vtable = { static const dc_parser_vtable_t diverite_nitekq_parser_vtable = {
sizeof(diverite_nitekq_parser_t), sizeof(diverite_nitekq_parser_t),
DC_FAMILY_DIVERITE_NITEKQ, DC_FAMILY_DIVERITE_NITEKQ,
diverite_nitekq_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -67,7 +69,7 @@ static const dc_parser_vtable_t diverite_nitekq_parser_vtable = {
dc_status_t dc_status_t
diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size) diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context)
{ {
diverite_nitekq_parser_t *parser = NULL; diverite_nitekq_parser_t *parser = NULL;
@ -75,7 +77,7 @@ diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context, const u
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (diverite_nitekq_parser_t *) dc_parser_allocate (context, &diverite_nitekq_parser_vtable, data, size); parser = (diverite_nitekq_parser_t *) dc_parser_allocate (context, &diverite_nitekq_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -99,6 +101,13 @@ diverite_nitekq_parser_create (dc_parser_t **out, dc_context_t *context, const u
} }
static dc_status_t
diverite_nitekq_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
return DC_STATUS_SUCCESS;
}
static dc_status_t static dc_status_t
diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) diverite_nitekq_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -152,7 +161,6 @@ diverite_nitekq_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, u
*((unsigned int *) value) = parser->ngasmixes; *((unsigned int *) value) = parser->ngasmixes;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = parser->he[flags] / 100.0; gasmix->helium = parser->he[flags] / 100.0;
gasmix->oxygen = parser->o2[flags] / 100.0; gasmix->oxygen = parser->o2[flags] / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -256,13 +264,13 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
// Time (seconds). // Time (seconds).
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Gas change // Gas change
if (gasmix != gasmix_previous) { if (gasmix != gasmix_previous) {
sample.gasmix = gasmix; sample.gasmix = gasmix;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix_previous = gasmix; gasmix_previous = gasmix;
} }
@ -274,7 +282,7 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
else else
sample.depth = depth * FEET / 10.0; sample.depth = depth * FEET / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
offset += 2; offset += 2;
if (type == 3) { if (type == 3) {
@ -285,9 +293,8 @@ diverite_nitekq_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac
if (offset + 1 > size) if (offset + 1 > size)
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
unsigned int ppo2 = data[offset]; unsigned int ppo2 = data[offset];
sample.ppo2.sensor = DC_SENSOR_NONE; sample.ppo2 = ppo2 / 100.0;
sample.ppo2.value = ppo2 / 100.0; if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
if (callback) callback (DC_SAMPLE_PPO2, &sample, userdata);
offset++; offset++;
} }
} else { } else {

View File

@ -35,7 +35,7 @@ dc_status_t
divesoft_freedom_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); divesoft_freedom_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
divesoft_freedom_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size); divesoft_freedom_parser_create (dc_parser_t **parser, dc_context_t *context);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -254,6 +254,7 @@ typedef struct divesoft_freedom_parser_t {
unsigned int calibrated; unsigned int calibrated;
} divesoft_freedom_parser_t; } 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_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_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); static dc_status_t divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -261,6 +262,7 @@ static dc_status_t divesoft_freedom_parser_samples_foreach (dc_parser_t *abstrac
static const dc_parser_vtable_t divesoft_freedom_parser_vtable = { static const dc_parser_vtable_t divesoft_freedom_parser_vtable = {
sizeof(divesoft_freedom_parser_t), sizeof(divesoft_freedom_parser_t),
DC_FAMILY_DIVESOFT_FREEDOM, DC_FAMILY_DIVESOFT_FREEDOM,
divesoft_freedom_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -641,7 +643,7 @@ divesoft_freedom_cache (divesoft_freedom_parser_t *parser)
} }
dc_status_t dc_status_t
divesoft_freedom_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size) divesoft_freedom_parser_create (dc_parser_t **out, dc_context_t *context)
{ {
divesoft_freedom_parser_t *parser = NULL; divesoft_freedom_parser_t *parser = NULL;
@ -649,7 +651,7 @@ divesoft_freedom_parser_create (dc_parser_t **out, dc_context_t *context, const
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (divesoft_freedom_parser_t *) dc_parser_allocate (context, &divesoft_freedom_parser_vtable, data, size); parser = (divesoft_freedom_parser_t *) dc_parser_allocate (context, &divesoft_freedom_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -696,6 +698,50 @@ divesoft_freedom_parser_create (dc_parser_t **out, dc_context_t *context, const
return DC_STATUS_SUCCESS; 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 static dc_status_t
divesoft_freedom_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) divesoft_freedom_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -709,21 +755,13 @@ divesoft_freedom_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *date
return status; return status;
unsigned int timestamp = array_uint32_le (data + 8); 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)) if (!dc_datetime_gmtime (datetime, ticks))
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
if (parser->version == HEADER_SIGNATURE_V2) { if (parser->version == HEADER_SIGNATURE_V2) {
datetime->timezone = timezone; datetime->timezone = ((signed short) array_uint16_le (data + 40)) * 60;
} else { } else {
datetime->timezone = DC_TIMEZONE_NONE; datetime->timezone = DC_TIMEZONE_NONE;
} }
@ -800,13 +838,6 @@ divesoft_freedom_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
*((unsigned int *) value) = parser->ngasmixes; *((unsigned int *) value) = parser->ngasmixes;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
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->helium = parser->gasmix[flags].helium / 100.0;
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0; gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -828,7 +859,6 @@ divesoft_freedom_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
tank->beginpressure = parser->tank[flags].beginpressure * 2.0; tank->beginpressure = parser->tank[flags].beginpressure * 2.0;
tank->endpressure = parser->tank[flags].endpressure * 2.0; tank->endpressure = parser->tank[flags].endpressure * 2.0;
tank->gasmix = flags; tank->gasmix = flags;
tank->usage = DC_USAGE_NONE;
break; break;
case DC_FIELD_DECOMODEL: case DC_FIELD_DECOMODEL:
if (parser->vpm) { if (parser->vpm) {
@ -894,15 +924,15 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
continue; continue;
} }
time = timestamp; time = timestamp;
sample.time = time * 1000; sample.time = time;
if (callback) callback(DC_SAMPLE_TIME, &sample, userdata); if (callback) callback(DC_SAMPLE_TIME, sample, userdata);
} }
// Initial diluent. // Initial diluent.
if (!initial) { if (!initial) {
if (parser->diluent != UNDEFINED) { if (parser->diluent != UNDEFINED) {
sample.gasmix = parser->diluent; sample.gasmix = parser->diluent;
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
} }
initial = 1; initial = 1;
} }
@ -913,19 +943,18 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
unsigned int ppo2 = array_uint16_le (data + offset + 6); unsigned int ppo2 = array_uint16_le (data + offset + 6);
sample.depth = depth / 100.0; sample.depth = depth / 100.0;
if (callback) callback(DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback(DC_SAMPLE_DEPTH, sample, userdata);
if (ppo2) { if (ppo2) {
sample.ppo2.sensor = DC_SENSOR_NONE; sample.ppo2 = ppo2 * 10.0 / BAR;
sample.ppo2.value = ppo2 * 10.0 / BAR; if (callback) callback(DC_SAMPLE_PPO2, sample, userdata);
if (callback) callback(DC_SAMPLE_PPO2, &sample, userdata);
} }
if (id == POINT_2) { if (id == POINT_2) {
unsigned int orientation = array_uint32_le (data + offset + 8); unsigned int orientation = array_uint32_le (data + offset + 8);
unsigned int heading = orientation & 0x1FF; unsigned int heading = orientation & 0x1FF;
sample.bearing = heading; 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) { } else if (id == POINT_1 || id == POINT_1_OLD) {
unsigned int misc = array_uint32_le (data + offset + 8); unsigned int misc = array_uint32_le (data + offset + 8);
unsigned int ceiling = array_uint16_le (data + offset + 12); unsigned int ceiling = array_uint16_le (data + offset + 12);
@ -936,7 +965,7 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
// Temperature // Temperature
sample.temperature = (signed int) signextend (temp, 10) / 10.0; 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 // Deco / NDL
if (ceiling) { if (ceiling) {
@ -948,13 +977,12 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
sample.deco.time = ndl * 60; sample.deco.time = ndl * 60;
sample.deco.depth = 0.0; sample.deco.depth = 0.0;
} }
sample.deco.tts = tts * 60; if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
if (callback) callback(DC_SAMPLE_DECO, &sample, userdata);
// Setpoint // Setpoint
if (setpoint) { if (setpoint) {
sample.setpoint = setpoint / 100.0; 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) { } else if ((type >= LREC_MANIPULATION && type <= LREC_ACTIVITY) || type == LREC_INFO) {
@ -966,7 +994,7 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
sample.event.time = 0; sample.event.time = 0;
sample.event.flags = 0; sample.event.flags = 0;
sample.event.value = 0; sample.event.value = 0;
if (callback) callback(DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback(DC_SAMPLE_EVENT, sample, userdata);
} else if (event == EVENT_MIX_CHANGED || event == EVENT_DILUENT || event == EVENT_CHANGE_MODE) { } else if (event == EVENT_MIX_CHANGED || event == EVENT_DILUENT || event == EVENT_CHANGE_MODE) {
unsigned int o2 = data[offset + 6]; unsigned int o2 = data[offset + 6];
unsigned int he = data[offset + 7]; unsigned int he = data[offset + 7];
@ -986,13 +1014,13 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
sample.gasmix = idx; sample.gasmix = idx;
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
} else if (event == EVENT_CNS) { } else if (event == EVENT_CNS) {
sample.cns = array_uint16_le (data + offset + 6) / 100.0; 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) { } else if (event == EVENT_SETPOINT_MANUAL || event == EVENT_SETPOINT_AUTO) {
sample.setpoint = data[6] / 100.0; 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) { } else if (type == LREC_MEASURE) {
// Measurement record. // Measurement record.
@ -1010,27 +1038,25 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
sample.pressure.tank = idx; sample.pressure.tank = idx;
sample.pressure.value = pressure * 2.0; 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) { } else if (id == MEASURE_ID_OXYGEN) {
for (unsigned int i = 0; i < NSENSORS; ++i) { for (unsigned int i = 0; i < NSENSORS; ++i) {
unsigned int ppo2 = array_uint16_le (data + offset + 4 + i * 2); unsigned int ppo2 = array_uint16_le (data + offset + 4 + i * 2);
if (ppo2 == 0 || ppo2 == 0xFFFF) if (ppo2 == 0 || ppo2 == 0xFFFF)
continue; continue;
sample.ppo2.sensor = i; sample.ppo2 = ppo2 * 10.0 / BAR;
sample.ppo2.value = ppo2 * 10.0 / BAR; if (callback) callback(DC_SAMPLE_PPO2, sample, userdata);
if (callback) callback(DC_SAMPLE_PPO2, &sample, userdata);
} }
} else if (id == MEASURE_ID_OXYGEN_MV) { } else if (id == MEASURE_ID_OXYGEN_MV) {
for (unsigned int i = 0; i < NSENSORS; ++i) { for (unsigned int i = 0; i < NSENSORS; ++i) {
unsigned int value = array_uint16_le (data + offset + 4 + i * 2); unsigned int value = array_uint16_le (data + offset + 4 + i * 2);
unsigned int state = data[offset + 12 + i]; unsigned int state = data[offset + 12 + i];
if (!parser->calibrated || parser->calibration[i] == 0 || if (!parser->calibrated || state == SENSTAT_UNCALIBRATED ||
state == SENSTAT_UNCALIBRATED || state == SENSTAT_NOT_EXIST) state == SENSTAT_NOT_EXIST)
continue; continue;
sample.ppo2.sensor = i; sample.ppo2 = value / 100.0 * parser->calibration[i] / BAR;
sample.ppo2.value = value / 100.0 * parser->calibration[i] / BAR; if (callback) callback(DC_SAMPLE_PPO2, sample, userdata);
if (callback) callback(DC_SAMPLE_PPO2, &sample, userdata);
} }
} }
} else if (type == LREC_STATE) { } else if (type == LREC_STATE) {

View File

@ -36,7 +36,7 @@ dc_status_t
divesystem_idive_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model); divesystem_idive_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
dc_status_t dc_status_t
divesystem_idive_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model); divesystem_idive_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -58,9 +58,6 @@
#define IX3M2_ZHL16C 2 #define IX3M2_ZHL16C 2
#define IX3M2_VPM 3 #define IX3M2_VPM 3
#define REC_SAMPLE 0
#define REC_INFO 1
typedef struct divesystem_idive_parser_t divesystem_idive_parser_t; typedef struct divesystem_idive_parser_t divesystem_idive_parser_t;
typedef struct divesystem_idive_gasmix_t { typedef struct divesystem_idive_gasmix_t {
@ -92,6 +89,7 @@ struct divesystem_idive_parser_t {
unsigned int gf_high; unsigned int gf_high;
}; };
static dc_status_t divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
static dc_status_t divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static dc_status_t divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -99,6 +97,7 @@ static dc_status_t divesystem_idive_parser_samples_foreach (dc_parser_t *abstrac
static const dc_parser_vtable_t divesystem_idive_parser_vtable = { static const dc_parser_vtable_t divesystem_idive_parser_vtable = {
sizeof(divesystem_idive_parser_t), sizeof(divesystem_idive_parser_t),
DC_FAMILY_DIVESYSTEM_IDIVE, DC_FAMILY_DIVESYSTEM_IDIVE,
divesystem_idive_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -110,7 +109,7 @@ static const dc_parser_vtable_t divesystem_idive_parser_vtable = {
dc_status_t dc_status_t
divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model) divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{ {
divesystem_idive_parser_t *parser = NULL; divesystem_idive_parser_t *parser = NULL;
@ -118,7 +117,7 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, const
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (divesystem_idive_parser_t *) dc_parser_allocate (context, &divesystem_idive_parser_vtable, data, size); parser = (divesystem_idive_parser_t *) dc_parser_allocate (context, &divesystem_idive_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -157,6 +156,35 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, const
} }
static dc_status_t
divesystem_idive_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size)
{
divesystem_idive_parser_t *parser = (divesystem_idive_parser_t *) abstract;
// Reset the cache.
parser->cached = 0;
parser->divemode = INVALID;
parser->divetime = 0;
parser->maxdepth = 0;
parser->ngasmixes = 0;
parser->ntanks = 0;
for (unsigned int i = 0; i < NGASMIXES; ++i) {
parser->gasmix[i].oxygen = 0;
parser->gasmix[i].helium = 0;
}
for (unsigned int i = 0; i < NTANKS; ++i) {
parser->tank[i].id = 0;
parser->tank[i].beginpressure = 0;
parser->tank[i].endpressure = 0;
}
parser->algorithm = INVALID;
parser->gf_low = INVALID;
parser->gf_high = INVALID;
return DC_STATUS_SUCCESS;
}
static dc_status_t static dc_status_t
divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -289,7 +317,6 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
*((unsigned int *) value) = parser->ngasmixes; *((unsigned int *) value) = parser->ngasmixes;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = parser->gasmix[flags].helium / 100.0; gasmix->helium = parser->gasmix[flags].helium / 100.0;
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0; gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -304,7 +331,6 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
tank->beginpressure = parser->tank[flags].beginpressure; tank->beginpressure = parser->tank[flags].beginpressure;
tank->endpressure = parser->tank[flags].endpressure; tank->endpressure = parser->tank[flags].endpressure;
tank->gasmix = DC_GASMIX_UNKNOWN; tank->gasmix = DC_GASMIX_UNKNOWN;
tank->usage = DC_USAGE_NONE;
break; break;
case DC_FIELD_ATMOSPHERIC: case DC_FIELD_ATMOSPHERIC:
if (ISIX3M(parser->model)) { if (ISIX3M(parser->model)) {
@ -413,7 +439,6 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
unsigned int algorithm_previous = INVALID; unsigned int algorithm_previous = INVALID;
unsigned int gf_low = INVALID; unsigned int gf_low = INVALID;
unsigned int gf_high = INVALID; unsigned int gf_high = INVALID;
unsigned int have_bearing = 0;
unsigned int firmware = 0; unsigned int firmware = 0;
unsigned int apos4 = 0; unsigned int apos4 = 0;
@ -442,37 +467,27 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
while (offset + samplesize <= size) { while (offset + samplesize <= size) {
dc_sample_value_t sample = {0}; dc_sample_value_t sample = {0};
// Get the record type.
unsigned int type = ISIX3M(parser->model) ?
array_uint16_le (data + offset + 52) :
REC_SAMPLE;
if (type != REC_SAMPLE) {
// Skip non-sample records.
offset += samplesize;
continue;
}
// Time (seconds). // Time (seconds).
unsigned int timestamp = array_uint32_le (data + offset + 2); unsigned int timestamp = array_uint32_le (data + offset + 2);
if (timestamp <= time && time != 0) { if (timestamp <= time) {
ERROR (abstract->context, "Timestamp moved backwards (%u %u).", timestamp, time); ERROR (abstract->context, "Timestamp moved backwards.");
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
time = timestamp; time = timestamp;
sample.time = timestamp * 1000; sample.time = timestamp;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/10 m). // Depth (1/10 m).
unsigned int depth = array_uint16_le (data + offset + 6); unsigned int depth = array_uint16_le (data + offset + 6);
if (maxdepth < depth) if (maxdepth < depth)
maxdepth = depth; maxdepth = depth;
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Temperature (Celsius). // Temperature (Celsius).
signed int temperature = (signed short) array_uint16_le (data + offset + 8); signed int temperature = (signed short) array_uint16_le (data + offset + 8);
sample.temperature = temperature / 10.0; sample.temperature = temperature / 10.0;
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
// Dive mode // Dive mode
unsigned int mode = data[offset + 18]; unsigned int mode = data[offset + 18];
@ -506,7 +521,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
if (mode == SCR || mode == CCR) { if (mode == SCR || mode == CCR) {
unsigned int setpoint = array_uint16_le (data + offset + 19); unsigned int setpoint = array_uint16_le (data + offset + 19);
sample.setpoint = setpoint / 1000.0; sample.setpoint = setpoint / 1000.0;
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata); if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
} }
// Gaschange. // Gaschange.
@ -533,7 +548,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
} }
sample.gasmix = i; sample.gasmix = i;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
o2_previous = o2; o2_previous = o2;
he_previous = he; he_previous = he;
} }
@ -551,20 +566,18 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
if (decostop) { if (decostop) {
sample.deco.type = DC_DECO_DECOSTOP; sample.deco.type = DC_DECO_DECOSTOP;
sample.deco.depth = decostop / 10.0; sample.deco.depth = decostop / 10.0;
sample.deco.time = decotime; sample.deco.time = apos4 ? decotime : tts;
sample.deco.tts = tts;
} else { } else {
sample.deco.type = DC_DECO_NDL; sample.deco.type = DC_DECO_NDL;
sample.deco.depth = 0.0; sample.deco.depth = 0.0;
sample.deco.time = tts; sample.deco.time = tts;
sample.deco.tts = 0;
} }
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata); if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
// CNS // CNS
unsigned int cns = array_uint16_le (data + offset + 29); unsigned int cns = array_uint16_le (data + offset + 29);
sample.cns = cns / 100.0; sample.cns = cns / 100.0;
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata); if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
// Tank Pressure // Tank Pressure
if (samplesize == SZ_SAMPLE_IX3M_APOS4) { if (samplesize == SZ_SAMPLE_IX3M_APOS4) {
@ -585,7 +598,7 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
sample.event.time = 0; sample.event.time = 0;
sample.event.flags = 0; sample.event.flags = 0;
sample.event.value = 0; sample.event.value = 0;
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
} else { } else {
// Get the index of the tank. // Get the index of the tank.
if (id != tank_previous) { if (id != tank_previous) {
@ -615,20 +628,10 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
if (tank_idx < ntanks) { if (tank_idx < ntanks) {
sample.pressure.tank = tank_idx; sample.pressure.tank = tank_idx;
sample.pressure.value = pressure; sample.pressure.value = pressure;
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata); if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
tank[tank_idx].endpressure = pressure; tank[tank_idx].endpressure = pressure;
} }
} }
// Compass bearing
unsigned int bearing = array_uint16_le (data + offset + 50);
if (bearing != 0) {
have_bearing = 1; // Stop ignoring zero values.
}
if (have_bearing && bearing != 0xFFFF) {
sample.bearing = bearing;
if (callback) callback (DC_SAMPLE_BEARING, &sample, userdata);
}
} }
offset += samplesize; offset += samplesize;

View File

@ -40,7 +40,7 @@
#define RB_PROFILE_BEGIN 0x000000 #define RB_PROFILE_BEGIN 0x000000
#define RB_PROFILE_END 0x200000 #define RB_PROFILE_END 0x200000
#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_EMPTY, RB_PROFILE_BEGIN, RB_PROFILE_END) #define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, 0, RB_PROFILE_BEGIN, RB_PROFILE_END)
#define READY 0x4D #define READY 0x4D
#define HEADER 0x61 #define HEADER 0x61

View File

@ -36,7 +36,7 @@ dc_status_t
hw_ostc_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); hw_ostc_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size); hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1715,10 +1715,6 @@ hw_ostc3_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
return rc; return rc;
} }
if (device->hardware == OSTC4) {
return DC_STATUS_UNSUPPORTED;
}
// Emit a device info event. // Emit a device info event.
dc_event_devinfo_t devinfo; dc_event_devinfo_t devinfo;
devinfo.firmware = device->firmware; devinfo.firmware = device->firmware;

View File

@ -36,7 +36,7 @@ dc_status_t
hw_ostc3_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); hw_ostc3_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model); hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -37,6 +37,10 @@
#define UNDEFINED 0xFFFFFFFF #define UNDEFINED 0xFFFFFFFF
#define ALL 0
#define FIXED 1
#define MANUAL 2
#define HEADER 1 #define HEADER 1
#define PROFILE 2 #define PROFILE 2
@ -104,12 +108,10 @@ typedef struct hw_ostc_layout_t {
} hw_ostc_layout_t; } hw_ostc_layout_t;
typedef struct hw_ostc_gasmix_t { typedef struct hw_ostc_gasmix_t {
unsigned int id;
unsigned int oxygen; unsigned int oxygen;
unsigned int helium; unsigned int helium;
unsigned int type; unsigned int type;
unsigned int enabled; unsigned int enabled;
unsigned int active;
unsigned int diluent; unsigned int diluent;
} hw_ostc_gasmix_t; } hw_ostc_gasmix_t;
@ -124,22 +126,21 @@ typedef struct hw_ostc_parser_t {
const hw_ostc_layout_t *layout; const hw_ostc_layout_t *layout;
unsigned int ngasmixes; unsigned int ngasmixes;
unsigned int nfixed; unsigned int nfixed;
unsigned int ndisabled;
unsigned int initial; unsigned int initial;
unsigned int initial_setpoint; unsigned int initial_setpoint;
unsigned int initial_cns; unsigned int initial_cns;
hw_ostc_gasmix_t gasmix[NGASMIXES]; hw_ostc_gasmix_t gasmix[NGASMIXES];
} hw_ostc_parser_t; } hw_ostc_parser_t;
static dc_status_t hw_ostc_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size);
static dc_status_t hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); static dc_status_t hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
static dc_status_t hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value); static dc_status_t hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value);
static dc_status_t hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata); static dc_status_t hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
static dc_status_t hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t callback, void *userdata);
static const dc_parser_vtable_t hw_ostc_parser_vtable = { static const dc_parser_vtable_t hw_ostc_parser_vtable = {
sizeof(hw_ostc_parser_t), sizeof(hw_ostc_parser_t),
DC_FAMILY_HW_OSTC, DC_FAMILY_HW_OSTC,
hw_ostc_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -195,10 +196,15 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc3 = {
}; };
static unsigned int static unsigned int
hw_ostc_find_gasmix_manual (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he, unsigned int dil) hw_ostc_find_gasmix (hw_ostc_parser_t *parser, unsigned int o2, unsigned int he, unsigned int dil, unsigned int type)
{ {
unsigned int offset = parser->nfixed - parser->ndisabled; unsigned int offset = 0;
unsigned int count = parser->ngasmixes; unsigned int count = parser->ngasmixes;
if (type == FIXED) {
count = parser->nfixed;
} else if (type == MANUAL) {
offset = parser->nfixed;
}
unsigned int i = offset; unsigned int i = offset;
while (i < count) { while (i < count) {
@ -210,22 +216,6 @@ hw_ostc_find_gasmix_manual (hw_ostc_parser_t *parser, unsigned int o2, unsigned
return i; return i;
} }
static unsigned int
hw_ostc_find_gasmix_fixed (hw_ostc_parser_t *parser, unsigned int id)
{
unsigned int offset = 0;
unsigned int count = parser->nfixed - parser->ndisabled;
unsigned int i = offset;
while (i < count) {
if (id == parser->gasmix[i].id)
break;
i++;
}
return i;
}
static unsigned int static unsigned int
hw_ostc_is_ccr (unsigned int divemode, unsigned int version) hw_ostc_is_ccr (unsigned int divemode, unsigned int version)
{ {
@ -307,23 +297,19 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
initial = data[31]; initial = data[31];
} }
for (unsigned int i = 0; i < ngasmixes; ++i) { for (unsigned int i = 0; i < ngasmixes; ++i) {
gasmix[i].id = i + 1;
gasmix[i].oxygen = data[25 + 2 * i]; gasmix[i].oxygen = data[25 + 2 * i];
gasmix[i].helium = 0; gasmix[i].helium = 0;
gasmix[i].type = 0; gasmix[i].type = 0;
gasmix[i].enabled = 1; gasmix[i].enabled = 1;
gasmix[i].active = 0;
gasmix[i].diluent = 0; gasmix[i].diluent = 0;
} }
} else if (version == 0x23 || version == 0x24) { } else if (version == 0x23 || version == 0x24) {
ngasmixes = 5; ngasmixes = 5;
for (unsigned int i = 0; i < ngasmixes; ++i) { for (unsigned int i = 0; i < ngasmixes; ++i) {
gasmix[i].id = i + 1;
gasmix[i].oxygen = data[28 + 4 * i + 0]; gasmix[i].oxygen = data[28 + 4 * i + 0];
gasmix[i].helium = data[28 + 4 * i + 1]; gasmix[i].helium = data[28 + 4 * i + 1];
gasmix[i].type = data[28 + 4 * i + 3]; gasmix[i].type = data[28 + 4 * i + 3];
gasmix[i].enabled = gasmix[i].type != 0; gasmix[i].enabled = gasmix[i].type != 0;
gasmix[i].active = 0;
gasmix[i].diluent = ccr; gasmix[i].diluent = ccr;
// Find the first gas marked as the initial gas. // Find the first gas marked as the initial gas.
if (initial == UNDEFINED && data[28 + 4 * i + 3] == 1) { if (initial == UNDEFINED && data[28 + 4 * i + 3] == 1) {
@ -342,7 +328,6 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
initial = data[31]; initial = data[31];
} }
for (unsigned int i = 0; i < ngasmixes; ++i) { for (unsigned int i = 0; i < ngasmixes; ++i) {
gasmix[i].id = i + 1;
gasmix[i].oxygen = data[19 + 2 * i + 0]; gasmix[i].oxygen = data[19 + 2 * i + 0];
gasmix[i].helium = data[19 + 2 * i + 1]; gasmix[i].helium = data[19 + 2 * i + 1];
gasmix[i].type = 0; gasmix[i].type = 0;
@ -351,7 +336,6 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
} else { } else {
gasmix[i].enabled = 1; gasmix[i].enabled = 1;
} }
gasmix[i].active = 0;
gasmix[i].diluent = ccr; gasmix[i].diluent = ccr;
} }
} }
@ -360,6 +344,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
ERROR(abstract->context, "Invalid initial gas mix."); ERROR(abstract->context, "Invalid initial gas mix.");
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
initial--; /* Convert to a zero based index. */
} else { } else {
WARNING(abstract->context, "No initial gas mix available."); WARNING(abstract->context, "No initial gas mix available.");
} }
@ -370,7 +355,6 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
parser->layout = layout; parser->layout = layout;
parser->ngasmixes = ngasmixes; parser->ngasmixes = ngasmixes;
parser->nfixed = ngasmixes; parser->nfixed = ngasmixes;
parser->ndisabled = 0;
parser->initial = initial; parser->initial = initial;
parser->initial_setpoint = initial_setpoint; parser->initial_setpoint = initial_setpoint;
parser->initial_cns = initial_cns; parser->initial_cns = initial_cns;
@ -383,7 +367,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
} }
static dc_status_t static dc_status_t
hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int hwos, unsigned int model) hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsigned int hwos, unsigned int model)
{ {
hw_ostc_parser_t *parser = NULL; hw_ostc_parser_t *parser = NULL;
@ -391,7 +375,7 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, const
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (hw_ostc_parser_t *) dc_parser_allocate (context, &hw_ostc_parser_vtable, data, size); parser = (hw_ostc_parser_t *) dc_parser_allocate (context, &hw_ostc_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -406,17 +390,14 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, const
parser->layout = NULL; parser->layout = NULL;
parser->ngasmixes = 0; parser->ngasmixes = 0;
parser->nfixed = 0; parser->nfixed = 0;
parser->ndisabled = 0;
parser->initial = 0; parser->initial = 0;
parser->initial_setpoint = 0; parser->initial_setpoint = 0;
parser->initial_cns = 0; parser->initial_cns = 0;
for (unsigned int i = 0; i < NGASMIXES; ++i) { for (unsigned int i = 0; i < NGASMIXES; ++i) {
parser->gasmix[i].id = 0;
parser->gasmix[i].oxygen = 0; parser->gasmix[i].oxygen = 0;
parser->gasmix[i].helium = 0; parser->gasmix[i].helium = 0;
parser->gasmix[i].type = 0; parser->gasmix[i].type = 0;
parser->gasmix[i].enabled = 0; parser->gasmix[i].enabled = 0;
parser->gasmix[i].active = 0;
parser->gasmix[i].diluent = 0; parser->gasmix[i].diluent = 0;
} }
@ -427,17 +408,44 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, const
dc_status_t dc_status_t
hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size) hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context)
{ {
return hw_ostc_parser_create_internal (out, context, data, size, 0, 0); return hw_ostc_parser_create_internal (out, context, 0, 0);
} }
dc_status_t dc_status_t
hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model) hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{ {
return hw_ostc_parser_create_internal (out, context, data, size, 1, model); return hw_ostc_parser_create_internal (out, context, 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 static dc_status_t
hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -511,7 +519,7 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
// Cache the profile data. // Cache the profile data.
if (parser->cached < PROFILE) { if (parser->cached < PROFILE) {
rc = hw_ostc_parser_internal_foreach (parser, NULL, NULL); rc = hw_ostc_parser_samples_foreach (abstract, NULL, NULL);
if (rc != DC_STATUS_SUCCESS) if (rc != DC_STATUS_SUCCESS)
return rc; return rc;
} }
@ -544,8 +552,6 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
*((unsigned int *) value) = parser->ngasmixes; *((unsigned int *) value) = parser->ngasmixes;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = parser->gasmix[flags].diluent ?
DC_USAGE_DILUENT : DC_USAGE_NONE;
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0; gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
gasmix->helium = parser->gasmix[flags].helium / 100.0; gasmix->helium = parser->gasmix[flags].helium / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -699,12 +705,17 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
static dc_status_t static dc_status_t
hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t callback, void *userdata) hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
{ {
dc_parser_t *abstract = (dc_parser_t *) parser; hw_ostc_parser_t *parser = (hw_ostc_parser_t *) abstract;
const unsigned char *data = abstract->data; const unsigned char *data = abstract->data;
unsigned int size = abstract->size; unsigned int size = abstract->size;
// Cache the parser data.
dc_status_t rc = hw_ostc_parser_cache (parser);
if (rc != DC_STATUS_SUCCESS)
return rc;
unsigned int version = parser->version; unsigned int version = parser->version;
unsigned int header = parser->header; unsigned int header = parser->header;
const hw_ostc_layout_t *layout = parser->layout; const hw_ostc_layout_t *layout = parser->layout;
@ -810,7 +821,7 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
unsigned int time = 0; unsigned int time = 0;
unsigned int nsamples = 0; unsigned int nsamples = 0;
unsigned int tank = parser->initial != UNDEFINED ? parser->initial - 1 : 0; unsigned int tank = parser->initial != UNDEFINED ? parser->initial : 0;
unsigned int offset = header; unsigned int offset = header;
if (version == 0x23 || version == 0x24) if (version == 0x23 || version == 0x24)
@ -822,33 +833,31 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
// Time (seconds). // Time (seconds).
time += samplerate; time += samplerate;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Initial gas mix. // Initial gas mix.
if (time == samplerate && parser->initial != UNDEFINED) { if (time == samplerate && parser->initial != UNDEFINED) {
unsigned int idx = hw_ostc_find_gasmix_fixed (parser, parser->initial); sample.gasmix = parser->initial;
parser->gasmix[idx].active = 1; if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata);
} }
// Initial setpoint (mbar). // Initial setpoint (mbar).
if (time == samplerate && parser->initial_setpoint != UNDEFINED) { if (time == samplerate && parser->initial_setpoint != UNDEFINED) {
sample.setpoint = parser->initial_setpoint / 100.0; sample.setpoint = parser->initial_setpoint / 100.0;
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata); if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
} }
// Initial CNS (%). // Initial CNS (%).
if (time == samplerate && parser->initial_cns != UNDEFINED) { if (time == samplerate && parser->initial_cns != UNDEFINED) {
sample.cns = parser->initial_cns / 100.0; sample.cns = parser->initial_cns / 100.0;
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata); if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
} }
// Depth (1/100 m). // Depth (1/100 m).
unsigned int depth = array_uint16_le (data + offset); unsigned int depth = array_uint16_le (data + offset);
sample.depth = depth / 100.0; sample.depth = depth / 100.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
offset += 2; offset += 2;
// Extended sample info. // Extended sample info.
@ -907,7 +916,7 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
break; break;
} }
if (sample.event.type && callback) if (sample.event.type && callback)
callback (DC_SAMPLE_EVENT, &sample, userdata); callback (DC_SAMPLE_EVENT, sample, userdata);
// Manual Gas Set & Change // Manual Gas Set & Change
if (events & 0x10) { if (events & 0x10) {
@ -917,24 +926,22 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
} }
unsigned int o2 = data[offset]; unsigned int o2 = data[offset];
unsigned int he = data[offset + 1]; unsigned int he = data[offset + 1];
unsigned int idx = hw_ostc_find_gasmix_manual (parser, o2, he, ccr); unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, ccr, MANUAL);
if (idx >= parser->ngasmixes) { if (idx >= parser->ngasmixes) {
if (idx >= NGASMIXES) { if (idx >= NGASMIXES) {
ERROR (abstract->context, "Maximum number of gas mixes reached."); ERROR (abstract->context, "Maximum number of gas mixes reached.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
} }
parser->gasmix[idx].id = 0;
parser->gasmix[idx].oxygen = o2; parser->gasmix[idx].oxygen = o2;
parser->gasmix[idx].helium = he; parser->gasmix[idx].helium = he;
parser->gasmix[idx].type = 0; parser->gasmix[idx].type = 0;
parser->gasmix[idx].enabled = 1; parser->gasmix[idx].enabled = 1;
parser->gasmix[idx].active = 1;
parser->gasmix[idx].diluent = ccr; parser->gasmix[idx].diluent = ccr;
parser->ngasmixes = idx + 1; parser->ngasmixes = idx + 1;
} }
sample.gasmix = idx; sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
offset += 2; offset += 2;
length -= 2; length -= 2;
} }
@ -945,20 +952,19 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
ERROR (abstract->context, "Buffer overflow detected!"); ERROR (abstract->context, "Buffer overflow detected!");
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
unsigned int id = data[offset]; unsigned int idx = data[offset];
if (parser->model == OSTC4 && ccr && id > parser->nfixed) { if (parser->model == OSTC4 && ccr && idx > parser->nfixed) {
// Fix the OSTC4 diluent index. // Fix the OSTC4 diluent index.
id -= parser->nfixed; idx -= parser->nfixed;
} }
if (id < 1 || id > parser->nfixed) { if (idx < 1 || idx > parser->nfixed) {
ERROR(abstract->context, "Invalid gas mix (%u).", id); ERROR(abstract->context, "Invalid gas mix (%u).", idx);
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
unsigned int idx = hw_ostc_find_gasmix_fixed (parser, id); idx--; /* Convert to a zero based index. */
parser->gasmix[idx].active = 1;
sample.gasmix = idx; sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
tank = id - 1; tank = idx;
offset++; offset++;
length--; length--;
} }
@ -971,7 +977,7 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
sample.setpoint = data[offset] / 100.0; sample.setpoint = data[offset] / 100.0;
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata); if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
offset++; offset++;
length--; length--;
} }
@ -985,24 +991,22 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
unsigned int o2 = data[offset]; unsigned int o2 = data[offset];
unsigned int he = data[offset + 1]; unsigned int he = data[offset + 1];
unsigned int idx = hw_ostc_find_gasmix_manual (parser, o2, he, 0); unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, 0, MANUAL);
if (idx >= parser->ngasmixes) { if (idx >= parser->ngasmixes) {
if (idx >= NGASMIXES) { if (idx >= NGASMIXES) {
ERROR (abstract->context, "Maximum number of gas mixes reached."); ERROR (abstract->context, "Maximum number of gas mixes reached.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
} }
parser->gasmix[idx].id = 0;
parser->gasmix[idx].oxygen = o2; parser->gasmix[idx].oxygen = o2;
parser->gasmix[idx].helium = he; parser->gasmix[idx].helium = he;
parser->gasmix[idx].type = 0; parser->gasmix[idx].type = 0;
parser->gasmix[idx].enabled = 1; parser->gasmix[idx].enabled = 1;
parser->gasmix[idx].active = 1;
parser->gasmix[idx].diluent = 0; parser->gasmix[idx].diluent = 0;
parser->ngasmixes = idx + 1; parser->ngasmixes = idx + 1;
} }
sample.gasmix = idx; sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
offset += 2; offset += 2;
length -= 2; length -= 2;
} }
@ -1034,7 +1038,7 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
case TEMPERATURE: case TEMPERATURE:
value = array_uint16_le (data + offset); value = array_uint16_le (data + offset);
sample.temperature = value / 10.0; sample.temperature = value / 10.0;
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
break; break;
case DECO: case DECO:
// Due to a firmware bug, the deco/ndl info is incorrect for // Due to a firmware bug, the deco/ndl info is incorrect for
@ -1049,8 +1053,7 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
sample.deco.depth = 0.0; sample.deco.depth = 0.0;
} }
sample.deco.time = data[offset + 1] * 60; sample.deco.time = data[offset + 1] * 60;
sample.deco.tts = 0; if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
break; break;
case PPO2: case PPO2:
for (unsigned int j = 0; j < 3; ++j) { for (unsigned int j = 0; j < 3; ++j) {
@ -1064,9 +1067,8 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
} }
if (count) { if (count) {
for (unsigned int j = 0; j < 3; ++j) { for (unsigned int j = 0; j < 3; ++j) {
sample.ppo2.sensor = i; sample.ppo2 = ppo2[j] / 100.0;
sample.ppo2.value = ppo2[j] / 100.0; if (callback) callback (DC_SAMPLE_PPO2, sample, userdata);
if (callback) callback (DC_SAMPLE_PPO2, &sample, userdata);
} }
} }
break; break;
@ -1075,7 +1077,7 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
sample.cns = array_uint16_le (data + offset) / 100.0; sample.cns = array_uint16_le (data + offset) / 100.0;
else else
sample.cns = data[offset] / 100.0; sample.cns = data[offset] / 100.0;
if (callback) callback (DC_SAMPLE_CNS, &sample, userdata); if (callback) callback (DC_SAMPLE_CNS, sample, userdata);
break; break;
case TANK: case TANK:
value = array_uint16_le (data + offset); value = array_uint16_le (data + offset);
@ -1088,7 +1090,7 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
(firmware >= OSTC3FW(10,40) && firmware <= OSTC3FW(10,50))) { (firmware >= OSTC3FW(10,40) && firmware <= OSTC3FW(10,50))) {
sample.pressure.value /= 10.0; sample.pressure.value /= 10.0;
} }
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata); if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
} }
break; break;
default: // Not yet used. default: // Not yet used.
@ -1108,7 +1110,7 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
sample.setpoint = data[offset] / 100.0; sample.setpoint = data[offset] / 100.0;
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata); if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
offset++; offset++;
length--; length--;
} }
@ -1122,24 +1124,22 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
unsigned int o2 = data[offset]; unsigned int o2 = data[offset];
unsigned int he = data[offset + 1]; unsigned int he = data[offset + 1];
unsigned int idx = hw_ostc_find_gasmix_manual (parser, o2, he, 0); unsigned int idx = hw_ostc_find_gasmix (parser, o2, he, 0, MANUAL);
if (idx >= parser->ngasmixes) { if (idx >= parser->ngasmixes) {
if (idx >= NGASMIXES) { if (idx >= NGASMIXES) {
ERROR (abstract->context, "Maximum number of gas mixes reached."); ERROR (abstract->context, "Maximum number of gas mixes reached.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
} }
parser->gasmix[idx].id = 0;
parser->gasmix[idx].oxygen = o2; parser->gasmix[idx].oxygen = o2;
parser->gasmix[idx].helium = he; parser->gasmix[idx].helium = he;
parser->gasmix[idx].type = 0; parser->gasmix[idx].type = 0;
parser->gasmix[idx].enabled = 1; parser->gasmix[idx].enabled = 1;
parser->gasmix[idx].active = 1;
parser->gasmix[idx].diluent = 0; parser->gasmix[idx].diluent = 0;
parser->ngasmixes = idx + 1; parser->ngasmixes = idx + 1;
} }
sample.gasmix = idx; sample.gasmix = idx;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
offset += 2; offset += 2;
length -= 2; length -= 2;
} }
@ -1157,50 +1157,7 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
// Remove the disabled gas mixes from the fixed gas mixes.
unsigned int ndisabled = 0, nenabled = 0;
unsigned int count = parser->nfixed - parser->ndisabled;
for (unsigned int i = 0; i < count; ++i) {
if (parser->gasmix[i].enabled || parser->gasmix[i].active) {
// Move the fixed gas mix.
parser->gasmix[nenabled] = parser->gasmix[i];
nenabled++;
} else {
ndisabled++;
}
}
// Move all the manual gas mixes.
memmove (parser->gasmix + nenabled, parser->gasmix + count,
(parser->ngasmixes - count) * sizeof (hw_ostc_gasmix_t));
memset (parser->gasmix + parser->ngasmixes - ndisabled, 0,
ndisabled * sizeof (hw_ostc_gasmix_t));
// Adjust the counts.
parser->ngasmixes -= ndisabled;
parser->ndisabled += ndisabled;
parser->cached = PROFILE; parser->cached = PROFILE;
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
} }
static dc_status_t
hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata)
{
hw_ostc_parser_t *parser = (hw_ostc_parser_t *) abstract;
// Cache the header data.
dc_status_t rc = hw_ostc_parser_cache (parser);
if (rc != DC_STATUS_SUCCESS)
return rc;
// Cache the profile data.
if (parser->cached < PROFILE) {
rc = hw_ostc_parser_internal_foreach (parser, NULL, NULL);
if (rc != DC_STATUS_SUCCESS)
return rc;
}
return hw_ostc_parser_internal_foreach (parser, callback, userdata);
}

View File

@ -47,6 +47,7 @@
#include "context-private.h" #include "context-private.h"
#include "iostream-private.h" #include "iostream-private.h"
#include "iterator-private.h" #include "iterator-private.h"
#include "descriptor-private.h"
#include "array.h" #include "array.h"
#include "platform.h" #include "platform.h"
@ -225,7 +226,7 @@ dc_irda_iterator_new (dc_iterator_t **out, dc_context_t *context, dc_descriptor_
INFO (context, "Discover: address=%08x, name=%s, charset=%02x, hints=%04x", INFO (context, "Discover: address=%08x, name=%s, charset=%02x, hints=%04x",
address, name, charset, hints); address, name, charset, hints);
if (!dc_descriptor_filter (descriptor, DC_TRANSPORT_IRDA, name)) { if (!dc_descriptor_filter (descriptor, DC_TRANSPORT_IRDA, name, NULL)) {
continue; continue;
} }

View File

@ -34,7 +34,6 @@ dc_descriptor_get_product
dc_descriptor_get_type dc_descriptor_get_type
dc_descriptor_get_model dc_descriptor_get_model
dc_descriptor_get_transports dc_descriptor_get_transports
dc_descriptor_filter
dc_iostream_get_transport dc_iostream_get_transport
dc_iostream_set_timeout dc_iostream_set_timeout
@ -92,11 +91,17 @@ dc_parser_set_clock
dc_parser_set_atmospheric dc_parser_set_atmospheric
dc_parser_set_density dc_parser_set_density
dc_parser_get_type dc_parser_get_type
dc_parser_set_data
dc_parser_get_datetime dc_parser_get_datetime
dc_parser_get_field dc_parser_get_field
dc_parser_samples_foreach dc_parser_samples_foreach
dc_parser_destroy 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_open
dc_device_close dc_device_close
dc_device_dump dc_device_dump

View File

@ -67,12 +67,12 @@
#define RB_LOGBOOK_BEGIN (1 * PAGESIZE) #define RB_LOGBOOK_BEGIN (1 * PAGESIZE)
#define RB_LOGBOOK_END (25 * PAGESIZE) #define RB_LOGBOOK_END (25 * PAGESIZE)
#define RB_LOGBOOK_SIZE (RB_LOGBOOK_END - RB_LOGBOOK_BEGIN) #define RB_LOGBOOK_SIZE (RB_LOGBOOK_END - RB_LOGBOOK_BEGIN)
#define RB_LOGBOOK_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_FULL, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END) #define RB_LOGBOOK_DISTANCE(a,b) ringbuffer_distance (a, b, 1, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END)
#define RB_PROFILE_BEGIN (25 * PAGESIZE) #define RB_PROFILE_BEGIN (25 * PAGESIZE)
#define RB_PROFILE_END (500 * PAGESIZE) #define RB_PROFILE_END (500 * PAGESIZE)
#define RB_PROFILE_SIZE (RB_PROFILE_END - RB_PROFILE_BEGIN) #define RB_PROFILE_SIZE (RB_PROFILE_END - RB_PROFILE_BEGIN)
#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_FULL, RB_PROFILE_BEGIN, RB_PROFILE_END) #define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, 1, RB_PROFILE_BEGIN, RB_PROFILE_END)
#define SZ_HEADER_XEN 80 #define SZ_HEADER_XEN 80
#define SZ_HEADER_OTHER 96 #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. // Create the ringbuffer stream.
dc_rbstream_t *rblogbook = NULL; dc_rbstream_t *rblogbook = NULL;
status = dc_rbstream_new (&rblogbook, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END, rb_logbook_end, DC_RBSTREAM_BACKWARD); status = dc_rbstream_new (&rblogbook, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END, rb_logbook_end);
if (status != DC_STATUS_SUCCESS) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream."); ERROR (abstract->context, "Failed to create the ringbuffer stream.");
goto error_free_logbook; 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. // Create the ringbuffer stream.
dc_rbstream_t *rbprofile = NULL; dc_rbstream_t *rbprofile = NULL;
status = dc_rbstream_new (&rbprofile, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_PROFILE_BEGIN, RB_PROFILE_END, rb_profile_end, DC_RBSTREAM_BACKWARD); status = dc_rbstream_new (&rbprofile, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_PROFILE_BEGIN, RB_PROFILE_END, rb_profile_end);
if (status != DC_STATUS_SUCCESS) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream."); ERROR (abstract->context, "Failed to create the ringbuffer stream.");
goto error_free_profile; goto error_free_profile;

View File

@ -35,7 +35,7 @@ dc_status_t
liquivision_lynx_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); liquivision_lynx_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
liquivision_lynx_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model); liquivision_lynx_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -117,6 +117,7 @@ struct liquivision_lynx_parser_t {
liquivision_lynx_tank_t tank[NTANKS]; 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_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_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); static dc_status_t liquivision_lynx_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -124,6 +125,7 @@ static dc_status_t liquivision_lynx_parser_samples_foreach (dc_parser_t *abstrac
static const dc_parser_vtable_t liquivision_lynx_parser_vtable = { static const dc_parser_vtable_t liquivision_lynx_parser_vtable = {
sizeof(liquivision_lynx_parser_t), sizeof(liquivision_lynx_parser_t),
DC_FAMILY_LIQUIVISION_LYNX, DC_FAMILY_LIQUIVISION_LYNX,
liquivision_lynx_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -135,7 +137,7 @@ static const dc_parser_vtable_t liquivision_lynx_parser_vtable = {
dc_status_t dc_status_t
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_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{ {
liquivision_lynx_parser_t *parser = NULL; liquivision_lynx_parser_t *parser = NULL;
@ -143,7 +145,7 @@ liquivision_lynx_parser_create (dc_parser_t **out, dc_context_t *context, const
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (liquivision_lynx_parser_t *) dc_parser_allocate (context, &liquivision_lynx_parser_vtable, data, size); parser = (liquivision_lynx_parser_t *) dc_parser_allocate (context, &liquivision_lynx_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -171,6 +173,29 @@ liquivision_lynx_parser_create (dc_parser_t **out, dc_context_t *context, const
} }
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 static dc_status_t
liquivision_lynx_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) liquivision_lynx_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -290,7 +315,6 @@ liquivision_lynx_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
*((unsigned int *) value) = parser->ngasmixes; *((unsigned int *) value) = parser->ngasmixes;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = parser->gasmix[flags].helium / 100.0; gasmix->helium = parser->gasmix[flags].helium / 100.0;
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0; gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -305,7 +329,6 @@ liquivision_lynx_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
tank->beginpressure = parser->tank[flags].beginpressure / 100.0; tank->beginpressure = parser->tank[flags].beginpressure / 100.0;
tank->endpressure = parser->tank[flags].endpressure / 100.0; tank->endpressure = parser->tank[flags].endpressure / 100.0;
tank->gasmix = DC_GASMIX_UNKNOWN; tank->gasmix = DC_GASMIX_UNKNOWN;
tank->usage = DC_USAGE_NONE;
break; break;
default: default:
return DC_STATUS_UNSUPPORTED; return DC_STATUS_UNSUPPORTED;
@ -522,29 +545,29 @@ liquivision_lynx_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
// Time (seconds). // Time (seconds).
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/100 m). // Depth (1/100 m).
sample.depth = value / 100.0; 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). // Temperature (1/10 °C).
int temperature = (signed short) array_uint16_le (data + offset); int temperature = (signed short) array_uint16_le (data + offset);
sample.temperature = temperature / 10.0; sample.temperature = temperature / 10.0;
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
// Gas mix // Gas mix
if (have_gasmix) { if (have_gasmix) {
sample.gasmix = gasmix_idx; sample.gasmix = gasmix_idx;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
have_gasmix = 0; have_gasmix = 0;
} }
// Setpoint (1/10 bar). // Setpoint (1/10 bar).
if (have_setpoint) { if (have_setpoint) {
sample.setpoint = setpoint / 10.0; sample.setpoint = setpoint / 10.0;
if (callback) callback (DC_SAMPLE_SETPOINT, &sample, userdata); if (callback) callback (DC_SAMPLE_SETPOINT, sample, userdata);
have_setpoint = 0; have_setpoint = 0;
} }
@ -554,7 +577,7 @@ liquivision_lynx_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
if (have_pressure & (1 << i)) { if (have_pressure & (1 << i)) {
sample.pressure.tank = i; sample.pressure.tank = i;
sample.pressure.value = pressure[i] / 100.0; 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; have_pressure = 0;
@ -570,8 +593,7 @@ liquivision_lynx_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
sample.deco.depth = 0.0; sample.deco.depth = 0.0;
} }
sample.deco.time = 0; sample.deco.time = 0;
sample.deco.tts = 0; if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
have_deco = 0; have_deco = 0;
} }

View File

@ -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); mares_darwin_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
dc_status_t dc_status_t
mares_darwin_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model); mares_darwin_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -47,6 +47,7 @@ struct mares_darwin_parser_t {
unsigned int samplesize; 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_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_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); static dc_status_t mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -54,6 +55,7 @@ static dc_status_t mares_darwin_parser_samples_foreach (dc_parser_t *abstract, d
static const dc_parser_vtable_t mares_darwin_parser_vtable = { static const dc_parser_vtable_t mares_darwin_parser_vtable = {
sizeof(mares_darwin_parser_t), sizeof(mares_darwin_parser_t),
DC_FAMILY_MARES_DARWIN, DC_FAMILY_MARES_DARWIN,
mares_darwin_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -65,7 +67,7 @@ static const dc_parser_vtable_t mares_darwin_parser_vtable = {
dc_status_t dc_status_t
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_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{ {
mares_darwin_parser_t *parser = NULL; mares_darwin_parser_t *parser = NULL;
@ -73,7 +75,7 @@ mares_darwin_parser_create (dc_parser_t **out, dc_context_t *context, const unsi
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (mares_darwin_parser_t *) dc_parser_allocate (context, &mares_darwin_parser_vtable, data, size); parser = (mares_darwin_parser_t *) dc_parser_allocate (context, &mares_darwin_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -95,6 +97,13 @@ mares_darwin_parser_create (dc_parser_t **out, dc_context_t *context, const unsi
} }
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 static dc_status_t
mares_darwin_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) mares_darwin_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -150,7 +159,6 @@ mares_darwin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
} }
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = 0.0; gasmix->helium = 0.0;
if (mode == NITROX) { if (mode == NITROX) {
gasmix->oxygen = p[0x0E] / 100.0; gasmix->oxygen = p[0x0E] / 100.0;
@ -177,7 +185,6 @@ mares_darwin_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
tank->gasmix = 0; tank->gasmix = 0;
tank->beginpressure = array_uint16_be (p + 0x17); tank->beginpressure = array_uint16_be (p + 0x17);
tank->endpressure = array_uint16_be (p + 0x19); tank->endpressure = array_uint16_be (p + 0x19);
tank->usage = DC_USAGE_NONE;
} else { } else {
return DC_STATUS_UNSUPPORTED; return DC_STATUS_UNSUPPORTED;
} }
@ -235,17 +242,17 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
// Surface Time (seconds). // Surface Time (seconds).
time += 20; time += 20;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/10 m). // Depth (1/10 m).
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Gas change. // Gas change.
if (gasmix != gasmix_previous) { if (gasmix != gasmix_previous) {
sample.gasmix = gasmix; sample.gasmix = gasmix;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix_previous = gasmix; gasmix_previous = gasmix;
} }
@ -255,7 +262,7 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
sample.event.time = 0; sample.event.time = 0;
sample.event.flags = 0; sample.event.flags = 0;
sample.event.value = ascent; sample.event.value = ascent;
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
} }
// Deco violation // Deco violation
@ -264,7 +271,7 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
sample.event.time = 0; sample.event.time = 0;
sample.event.flags = 0; sample.event.flags = 0;
sample.event.value = 0; sample.event.value = 0;
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
} }
// Deco stop // Deco stop
@ -275,8 +282,7 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
} }
sample.deco.time = 0; sample.deco.time = 0;
sample.deco.depth = 0.0; sample.deco.depth = 0.0;
sample.deco.tts = 0; if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
if (parser->samplesize == 3) { if (parser->samplesize == 3) {
unsigned int type = (time / 20 + 2) % 3; unsigned int type = (time / 20 + 2) % 3;
@ -285,7 +291,7 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
pressure -= abstract->data[offset + 2]; pressure -= abstract->data[offset + 2];
sample.pressure.tank = 0; sample.pressure.tank = 0;
sample.pressure.value = pressure; sample.pressure.value = pressure;
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata); if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
} }
} }

View File

@ -21,6 +21,7 @@
#include <string.h> // memcpy, memcmp #include <string.h> // memcpy, memcmp
#include <stdlib.h> // malloc, free #include <stdlib.h> // malloc, free
#include <assert.h> // assert
#include "mares_iconhd.h" #include "mares_iconhd.h"
#include "context-private.h" #include "context-private.h"
@ -48,39 +49,11 @@
#define SMARTAIR 0x24 #define SMARTAIR 0x24
#define QUAD 0x29 #define QUAD 0x29
#define HORIZON 0x2C #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 MAXRETRIES 4
#define MAXPACKET 244
#define FIXED 0
#define VARIABLE 1
#define ACK 0xAA #define ACK 0xAA
#define END 0xEA #define EOF 0xEA
#define XOR 0xA5 #define XOR 0xA5
#define CMD_VERSION 0xC2 #define CMD_VERSION 0xC2
@ -90,8 +63,6 @@
#define CMD_OBJ_EVEN 0xAC #define CMD_OBJ_EVEN 0xAC
#define CMD_OBJ_ODD 0xFE #define CMD_OBJ_ODD 0xFE
#define OBJ_DEVICE 0x2000
#define OBJ_DEVICE_SERIAL 0x04
#define OBJ_LOGBOOK 0x2008 #define OBJ_LOGBOOK 0x2008
#define OBJ_LOGBOOK_COUNT 0x01 #define OBJ_LOGBOOK_COUNT 0x01
#define OBJ_DIVE 0x3000 #define OBJ_DIVE 0x3000
@ -123,7 +94,6 @@ typedef struct mares_iconhd_device_t {
unsigned char version[140]; unsigned char version[140];
unsigned int model; unsigned int model;
unsigned int packetsize; unsigned int packetsize;
unsigned int ble;
} mares_iconhd_device_t; } mares_iconhd_device_t;
static dc_status_t mares_iconhd_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size); static dc_status_t mares_iconhd_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
@ -191,10 +161,6 @@ mares_iconhd_get_model (mares_iconhd_device_t *device)
{"Smart Air", SMARTAIR}, {"Smart Air", SMARTAIR},
{"Quad", QUAD}, {"Quad", QUAD},
{"Horizon", HORIZON}, {"Horizon", HORIZON},
{"Puck Air 2", PUCKAIR2},
{"Sirius", SIRIUS},
{"Quad Ci", QUADCI},
{"Puck4", PUCK4},
}; };
// Check the product name in the version packet against the list // Check the product name in the version packet against the list
@ -211,57 +177,44 @@ mares_iconhd_get_model (mares_iconhd_device_t *device)
} }
static dc_status_t static dc_status_t
mares_iconhd_packet_fixed (mares_iconhd_device_t *device, mares_iconhd_packet (mares_iconhd_device_t *device,
unsigned char cmd, const unsigned char command[], unsigned int csize,
const unsigned char data[], unsigned int size, unsigned char answer[], unsigned int asize)
unsigned char answer[], unsigned int asize,
unsigned int *actual)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
dc_transport_t transport = dc_iostream_get_transport (device->iostream);
assert (csize >= 2);
if (device_is_cancelled (abstract)) if (device_is_cancelled (abstract))
return DC_STATUS_CANCELLED; return DC_STATUS_CANCELLED;
// Send the command header to the dive computer. // Send the command header to the dive computer.
const unsigned char command[2] = { status = dc_iostream_write (device->iostream, command, 2, NULL);
cmd, cmd ^ XOR,
};
status = dc_iostream_write (device->iostream, command, sizeof(command), NULL);
if (status != DC_STATUS_SUCCESS) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command header."); ERROR (abstract->context, "Failed to send the command.");
return status; 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. // Receive the header byte.
unsigned char header[1] = {0}; unsigned char header[1] = {0};
status = dc_iostream_read (device->iostream, header, sizeof (header), NULL); status = dc_iostream_read (device->iostream, header, sizeof (header), NULL);
if (status != DC_STATUS_SUCCESS) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the packet header."); ERROR (abstract->context, "Failed to receive the answer.");
return status; return status;
} }
// Verify the header byte. // Verify the header byte.
if (header[0] != ACK) { if (header[0] != ACK) {
ERROR (abstract->context, "Unexpected packet header byte (%02x).", header[0]); ERROR (abstract->context, "Unexpected answer byte.");
return DC_STATUS_PROTOCOL; return DC_STATUS_PROTOCOL;
} }
// Send the command payload to the dive computer. // Send the command payload to the dive computer.
if (size && transport != DC_TRANSPORT_BLE) { if (csize > 2) {
status = dc_iostream_write (device->iostream, data, size, NULL); status = dc_iostream_write (device->iostream, command + 2, csize - 2, NULL);
if (status != DC_STATUS_SUCCESS) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to send the command data."); ERROR (abstract->context, "Failed to send the command.");
return status; return status;
} }
} }
@ -269,7 +222,7 @@ mares_iconhd_packet_fixed (mares_iconhd_device_t *device,
// Read the packet. // Read the packet.
status = dc_iostream_read (device->iostream, answer, asize, NULL); status = dc_iostream_read (device->iostream, answer, asize, NULL);
if (status != DC_STATUS_SUCCESS) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the packet data."); ERROR (abstract->context, "Failed to receive the answer.");
return status; return status;
} }
@ -277,130 +230,25 @@ mares_iconhd_packet_fixed (mares_iconhd_device_t *device,
unsigned char trailer[1] = {0}; unsigned char trailer[1] = {0};
status = dc_iostream_read (device->iostream, trailer, sizeof (trailer), NULL); status = dc_iostream_read (device->iostream, trailer, sizeof (trailer), NULL);
if (status != DC_STATUS_SUCCESS) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to receive the packet trailer."); ERROR (abstract->context, "Failed to receive the answer.");
return status; return status;
} }
// Verify the trailer byte. // Verify the trailer byte.
if (trailer[0] != END) { if (trailer[0] != EOF) {
ERROR (abstract->context, "Unexpected packet trailer byte (%02x).", trailer[0]); ERROR (abstract->context, "Unexpected answer byte.");
return DC_STATUS_PROTOCOL; return DC_STATUS_PROTOCOL;
} }
if (actual) {
*actual = asize;
}
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
} }
static dc_status_t static dc_status_t
mares_iconhd_packet_variable (mares_iconhd_device_t *device, mares_iconhd_transfer (mares_iconhd_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize)
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; unsigned int nretries = 0;
dc_status_t rc = DC_STATUS_SUCCESS; dc_status_t rc = DC_STATUS_SUCCESS;
while ((rc = mares_iconhd_packet (device, cmd, data, size, answer, asize, actual)) != DC_STATUS_SUCCESS) { while ((rc = mares_iconhd_packet (device, command, csize, answer, asize)) != DC_STATUS_SUCCESS) {
// Automatically discard a corrupted packet, // Automatically discard a corrupted packet,
// and request a new one. // and request a new one.
if (rc != DC_STATUS_PROTOCOL && rc != DC_STATUS_TIMEOUT) if (rc != DC_STATUS_PROTOCOL && rc != DC_STATUS_TIMEOUT)
@ -424,9 +272,7 @@ mares_iconhd_read_object(mares_iconhd_device_t *device, dc_event_progress_t *pro
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device; dc_device_t *abstract = (dc_device_t *) device;
dc_transport_t transport = dc_iostream_get_transport (device->iostream); dc_transport_t transport = dc_iostream_get_transport (device->iostream);
const unsigned int maxpacket = (transport == DC_TRANSPORT_BLE) ? const unsigned int maxpacket = (transport == DC_TRANSPORT_BLE) ? 124 : 504;
(device->ble == VARIABLE ? MAXPACKET - 3 : 124) :
504;
// Update and emit a progress event. // Update and emit a progress event.
unsigned int initial = 0; unsigned int initial = 0;
@ -437,21 +283,23 @@ mares_iconhd_read_object(mares_iconhd_device_t *device, dc_event_progress_t *pro
// Transfer the init packet. // Transfer the init packet.
unsigned char rsp_init[16]; unsigned char rsp_init[16];
unsigned char cmd_init[16] = { unsigned char cmd_init[18] = {
CMD_OBJ_INIT,
CMD_OBJ_INIT ^ XOR,
0x40, 0x40,
(index >> 0) & 0xFF, (index >> 0) & 0xFF,
(index >> 8) & 0xFF, (index >> 8) & 0xFF,
subindex & 0xFF subindex & 0xFF
}; };
memset (cmd_init + 6, 0x00, sizeof(cmd_init) - 6); memset (cmd_init + 6, 0x00, sizeof(cmd_init) - 6);
status = mares_iconhd_transfer (device, CMD_OBJ_INIT, cmd_init, sizeof (cmd_init), rsp_init, sizeof (rsp_init), NULL); status = mares_iconhd_transfer (device, cmd_init, sizeof (cmd_init), rsp_init, sizeof (rsp_init));
if (status != DC_STATUS_SUCCESS) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to transfer the init packet."); ERROR (abstract->context, "Failed to transfer the init packet.");
return status; return status;
} }
// Verify the packet header. // Verify the packet header.
if (memcmp (cmd_init + 1, rsp_init + 1, 3) != 0) { if (memcmp (cmd_init + 3, rsp_init + 1, 3) != 0) {
ERROR (abstract->context, "Unexpected packet header."); ERROR (abstract->context, "Unexpected packet header.");
return DC_STATUS_PROTOCOL; return DC_STATUS_PROTOCOL;
} }
@ -498,21 +346,14 @@ mares_iconhd_read_object(mares_iconhd_device_t *device, dc_event_progress_t *pro
} }
// Transfer the segment packet. // Transfer the segment packet.
unsigned int length = 0;
unsigned char rsp_segment[1 + 504]; unsigned char rsp_segment[1 + 504];
status = mares_iconhd_transfer (device, cmd, NULL, 0, rsp_segment, len + 1, &length); unsigned char cmd_segment[] = {cmd, cmd ^ XOR};
status = mares_iconhd_transfer (device, cmd_segment, sizeof (cmd_segment), rsp_segment, len + 1);
if (status != DC_STATUS_SUCCESS) { if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to transfer the segment packet."); ERROR (abstract->context, "Failed to transfer the segment packet.");
return status; return status;
} }
if (length < 1) {
ERROR (abstract->context, "Unexpected packet length (%u).", length);
return DC_STATUS_PROTOCOL;
}
length--;
// Verify the packet header. // Verify the packet header.
if ((rsp_segment[0] & 0xF0) >> 4 != toggle) { if ((rsp_segment[0] & 0xF0) >> 4 != toggle) {
ERROR (abstract->context, "Unexpected packet header (%02x).", rsp_segment[0]); ERROR (abstract->context, "Unexpected packet header (%02x).", rsp_segment[0]);
@ -520,12 +361,12 @@ mares_iconhd_read_object(mares_iconhd_device_t *device, dc_event_progress_t *pro
} }
// Append the payload to the output buffer. // Append the payload to the output buffer.
if (!dc_buffer_append (buffer, rsp_segment + 1, length)) { if (!dc_buffer_append (buffer, rsp_segment + 1, len)) {
ERROR (abstract->context, "Insufficient buffer space available."); ERROR (abstract->context, "Insufficient buffer space available.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
} }
nbytes += length; nbytes += len;
npackets++; npackets++;
// Update and emit the progress events. // Update and emit the progress events.
@ -539,7 +380,7 @@ mares_iconhd_read_object(mares_iconhd_device_t *device, dc_event_progress_t *pro
} }
dc_status_t dc_status_t
mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream, unsigned int model) mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream)
{ {
dc_status_t status = DC_STATUS_SUCCESS; dc_status_t status = DC_STATUS_SUCCESS;
mares_iconhd_device_t *device = NULL; mares_iconhd_device_t *device = NULL;
@ -562,11 +403,10 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_
memset (device->version, 0, sizeof (device->version)); memset (device->version, 0, sizeof (device->version));
device->model = 0; device->model = 0;
device->packetsize = 0; device->packetsize = 0;
device->ble = ISSIRIUS(model) ? VARIABLE : FIXED;
// Create the packet stream. // Create the packet stream.
if (transport == DC_TRANSPORT_BLE && device->ble == FIXED) { if (transport == DC_TRANSPORT_BLE) {
status = dc_packet_open (&device->iostream, context, iostream, 244, 20); status = dc_packet_open (&device->iostream, context, iostream, 20, 20);
if (status != DC_STATUS_SUCCESS) { if (status != DC_STATUS_SUCCESS) {
ERROR (context, "Failed to create the packet stream."); ERROR (context, "Failed to create the packet stream.");
goto error_free; goto error_free;
@ -607,8 +447,9 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_
dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); dc_iostream_purge (device->iostream, DC_DIRECTION_ALL);
// Send the version command. // Send the version command.
status = mares_iconhd_transfer (device, CMD_VERSION, NULL, 0, unsigned char command[] = {CMD_VERSION, CMD_VERSION ^ XOR};
device->version, sizeof (device->version), NULL); status = mares_iconhd_transfer (device, command, sizeof (command),
device->version, sizeof (device->version));
if (status != DC_STATUS_SUCCESS) { if (status != DC_STATUS_SUCCESS) {
goto error_free_iostream; goto error_free_iostream;
} }
@ -619,8 +460,9 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_
// Read the size of the flash memory. // Read the size of the flash memory.
unsigned int memsize = 0; unsigned int memsize = 0;
if (device->model == QUAD) { if (device->model == QUAD) {
unsigned char cmd_flash[] = {CMD_FLASHSIZE, CMD_FLASHSIZE ^ XOR};
unsigned char rsp_flash[4] = {0}; unsigned char rsp_flash[4] = {0};
status = mares_iconhd_transfer (device, CMD_FLASHSIZE, NULL, 0, rsp_flash, sizeof (rsp_flash), NULL); status = mares_iconhd_transfer (device, cmd_flash, sizeof (cmd_flash), rsp_flash, sizeof (rsp_flash));
if (status != DC_STATUS_SUCCESS) { if (status != DC_STATUS_SUCCESS) {
WARNING (context, "Failed to read the flash memory size."); WARNING (context, "Failed to read the flash memory size.");
} else { } else {
@ -679,7 +521,7 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_
error_free_iostream: error_free_iostream:
if (transport == DC_TRANSPORT_BLE && device->ble == FIXED) { if (transport == DC_TRANSPORT_BLE) {
dc_iostream_close (device->iostream); dc_iostream_close (device->iostream);
} }
error_free: error_free:
@ -692,10 +534,9 @@ static dc_status_t
mares_iconhd_device_close (dc_device_t *abstract) mares_iconhd_device_close (dc_device_t *abstract)
{ {
mares_iconhd_device_t *device = (mares_iconhd_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. // Close the packet stream.
if (transport == DC_TRANSPORT_BLE && device->ble == FIXED) { if (dc_iostream_get_transport (device->iostream) == DC_TRANSPORT_BLE) {
return dc_iostream_close (device->iostream); return dc_iostream_close (device->iostream);
} }
@ -734,7 +575,7 @@ mares_iconhd_device_read (dc_device_t *abstract, unsigned int address, unsigned
len = device->packetsize; len = device->packetsize;
// Read the packet. // Read the packet.
unsigned char command[] = { unsigned char command[] = {CMD_READ, CMD_READ ^ XOR,
(address ) & 0xFF, (address ) & 0xFF,
(address >> 8) & 0xFF, (address >> 8) & 0xFF,
(address >> 16) & 0xFF, (address >> 16) & 0xFF,
@ -743,7 +584,7 @@ mares_iconhd_device_read (dc_device_t *abstract, unsigned int address, unsigned
(len >> 8) & 0xFF, (len >> 8) & 0xFF,
(len >> 16) & 0xFF, (len >> 16) & 0xFF,
(len >> 24) & 0xFF}; (len >> 24) & 0xFF};
rc = mares_iconhd_transfer (device, CMD_READ, command, sizeof (command), data, len, NULL); rc = mares_iconhd_transfer (device, command, sizeof (command), data, len);
if (rc != DC_STATUS_SUCCESS) if (rc != DC_STATUS_SUCCESS)
return rc; return rc;
@ -800,21 +641,6 @@ mares_iconhd_device_foreach_raw (dc_device_t *abstract, dc_dive_callback_t callb
const mares_iconhd_layout_t *layout = device->layout; 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. // Enable progress notifications.
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
progress.maximum = layout->rb_profile_end - layout->rb_profile_begin; progress.maximum = layout->rb_profile_end - layout->rb_profile_begin;
@ -864,7 +690,7 @@ mares_iconhd_device_foreach_raw (dc_device_t *abstract, dc_dive_callback_t callb
// Create the ringbuffer stream. // Create the ringbuffer stream.
dc_rbstream_t *rbstream = NULL; dc_rbstream_t *rbstream = NULL;
rc = dc_rbstream_new (&rbstream, abstract, 1, device->packetsize, layout->rb_profile_begin, layout->rb_profile_end, eop, DC_RBSTREAM_BACKWARD); rc = dc_rbstream_new (&rbstream, abstract, 1, device->packetsize, layout->rb_profile_begin, layout->rb_profile_end, eop);
if (rc != DC_STATUS_SUCCESS) { if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream."); ERROR (abstract->context, "Failed to create the ringbuffer stream.");
return rc; return rc;
@ -891,7 +717,7 @@ mares_iconhd_device_foreach_raw (dc_device_t *abstract, dc_dive_callback_t callb
// Get the number of samples in the profile data. // Get the number of samples in the profile data.
unsigned int type = 0, nsamples = 0; unsigned int type = 0, nsamples = 0;
if (ISSMART(model)) { if (model == SMART || model == SMARTAPNEA || model == SMARTAIR) {
type = array_uint16_le (buffer + offset - header + 2); type = array_uint16_le (buffer + offset - header + 2);
nsamples = array_uint16_le (buffer + offset - header + 0); nsamples = array_uint16_le (buffer + offset - header + 0);
} else { } else {
@ -1020,33 +846,6 @@ mares_iconhd_device_foreach_object (dc_device_t *abstract, dc_dive_callback_t ca
return DC_STATUS_NOMEMORY; 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. // Read the number of dives.
rc = mares_iconhd_read_object (device, NULL, buffer, OBJ_LOGBOOK, OBJ_LOGBOOK_COUNT); rc = mares_iconhd_read_object (device, NULL, buffer, OBJ_LOGBOOK, OBJ_LOGBOOK_COUNT);
if (rc != DC_STATUS_SUCCESS) { if (rc != DC_STATUS_SUCCESS) {
@ -1109,6 +908,7 @@ mares_iconhd_device_foreach_object (dc_device_t *abstract, dc_dive_callback_t ca
static dc_status_t static dc_status_t
mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata) 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; mares_iconhd_device_t *device = (mares_iconhd_device_t *) abstract;
// Emit a vendor event. // Emit a vendor event.
@ -1117,7 +917,22 @@ mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback,
vendor.size = sizeof (device->version); vendor.size = sizeof (device->version);
device_event_emit (abstract, DC_EVENT_VENDOR, &vendor); device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
if (ISGENIUS(device->model)) { // 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) {
return mares_iconhd_device_foreach_object (abstract, callback, userdata); return mares_iconhd_device_foreach_object (abstract, callback, userdata);
} else { } else {
return mares_iconhd_device_foreach_raw (abstract, callback, userdata); return mares_iconhd_device_foreach_raw (abstract, callback, userdata);

View File

@ -32,10 +32,10 @@ extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
dc_status_t dc_status_t
mares_iconhd_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model); mares_iconhd_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
mares_iconhd_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model); mares_iconhd_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -45,23 +45,6 @@
#define QUADAIR 0x23 #define QUADAIR 0x23
#define SMARTAIR 0x24 #define SMARTAIR 0x24
#define HORIZON 0x2C #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_ICONHD 3
#define NGASMIXES_GENIUS 5 #define NGASMIXES_GENIUS 5
@ -281,6 +264,7 @@ static const mares_iconhd_layout_t horizon = {
0x54 + 8, /* tanks */ 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_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_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); static dc_status_t mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -288,6 +272,7 @@ static dc_status_t mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, d
static const dc_parser_vtable_t mares_iconhd_parser_vtable = { static const dc_parser_vtable_t mares_iconhd_parser_vtable = {
sizeof(mares_iconhd_parser_t), sizeof(mares_iconhd_parser_t),
DC_FAMILY_MARES_ICONHD, DC_FAMILY_MARES_ICONHD,
mares_iconhd_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -297,6 +282,28 @@ static const dc_parser_vtable_t mares_iconhd_parser_vtable = {
NULL /* destroy */ 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 static dc_status_t
mares_iconhd_cache (mares_iconhd_parser_t *parser) mares_iconhd_cache (mares_iconhd_parser_t *parser)
{ {
@ -327,7 +334,7 @@ mares_iconhd_cache (mares_iconhd_parser_t *parser)
// Get the number of samples in the profile data. // Get the number of samples in the profile data.
unsigned int type = 0, nsamples = 0; unsigned int type = 0, nsamples = 0;
if (ISSMART (parser->model)) { if (parser->model == SMART || parser->model == SMARTAPNEA || parser->model == SMARTAIR) {
type = array_uint16_le (data + length - header + 2); type = array_uint16_le (data + length - header + 2);
nsamples = array_uint16_le (data + length - header + 0); nsamples = array_uint16_le (data + length - header + 0);
} else { } else {
@ -382,7 +389,7 @@ mares_iconhd_cache (mares_iconhd_parser_t *parser)
} }
const unsigned char *p = data + length - headersize; const unsigned char *p = data + length - headersize;
if (!ISSMART(parser->model)) { if (parser->model != SMART && parser->model != SMARTAPNEA && parser->model != SMARTAIR) {
p += 4; p += 4;
} }
@ -394,12 +401,12 @@ mares_iconhd_cache (mares_iconhd_parser_t *parser)
unsigned int samplerate = 0; unsigned int samplerate = 0;
if (parser->model == SMARTAPNEA) { if (parser->model == SMARTAPNEA) {
unsigned int idx = (settings & 0x0600) >> 9; unsigned int idx = (settings & 0x0600) >> 9;
interval = 1;
samplerate = 1 << idx; samplerate = 1 << idx;
interval = 1000 / samplerate;
} else { } else {
const unsigned int intervals[] = {1, 5, 10, 20}; const unsigned int intervals[] = {1, 5, 10, 20};
unsigned int idx = (settings & 0x0C00) >> 10; unsigned int idx = (settings & 0x0C00) >> 10;
interval = intervals[idx] * 1000; interval = intervals[idx];
samplerate = 1; samplerate = 1;
} }
@ -540,22 +547,30 @@ mares_genius_cache (mares_iconhd_parser_t *parser)
// Get the dive mode. // Get the dive mode.
unsigned int mode = settings & 0xF; 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). // Get the surface timeout setting (in minutes).
// For older firmware versions the value is hardcoded to 3 minutes, but // 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 // 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 // stored in the settings. To detect whether the setting is available, we
// need to check the profile version instead of the header version. // need to check the profile version instead of the header version.
unsigned int surftime = 3; unsigned int surftime = 3;
if (headersize + 4 <= size) { if (profile_type == 0 &&
// Get the profile type and version. OBJVERSION(profile_major,profile_minor) >= OBJVERSION(1,0)) {
unsigned int profile_type = array_uint16_le (data + headersize); surftime = (settings >> 13) & 0x3F;
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. // Gas mixes and tanks.
@ -606,11 +621,11 @@ mares_genius_cache (mares_iconhd_parser_t *parser)
parser->logformat = logformat; parser->logformat = logformat;
parser->mode = mode; parser->mode = mode;
parser->nsamples = nsamples; parser->nsamples = nsamples;
parser->samplesize = 0; parser->samplesize = samplesize;
parser->headersize = headersize; parser->headersize = headersize;
parser->settings = settings; parser->settings = settings;
parser->surftime = surftime * 60; parser->surftime = surftime * 60;
parser->interval = 5000; parser->interval = 5;
parser->samplerate = 1; parser->samplerate = 1;
parser->ntanks = ntanks; parser->ntanks = ntanks;
parser->ngasmixes = ngasmixes; parser->ngasmixes = ngasmixes;
@ -633,7 +648,7 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser)
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
} }
if (ISGENIUS(parser->model)) { if (parser->model == GENIUS || parser->model == HORIZON) {
return mares_genius_cache (parser); return mares_genius_cache (parser);
} else { } else {
return mares_iconhd_cache (parser); return mares_iconhd_cache (parser);
@ -641,7 +656,7 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser)
} }
dc_status_t dc_status_t
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_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{ {
mares_iconhd_parser_t *parser = NULL; mares_iconhd_parser_t *parser = NULL;
@ -649,7 +664,7 @@ mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, const unsi
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (mares_iconhd_parser_t *) dc_parser_allocate (context, &mares_iconhd_parser_vtable, data, size); parser = (mares_iconhd_parser_t *) dc_parser_allocate (context, &mares_iconhd_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -659,7 +674,7 @@ mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, const unsi
parser->model = model; parser->model = model;
parser->cached = 0; parser->cached = 0;
parser->logformat = 0; parser->logformat = 0;
parser->mode = ISGENIUS(model) ? GENIUS_AIR : ICONHD_AIR; parser->mode = (model == GENIUS || model == HORIZON) ? GENIUS_AIR : ICONHD_AIR;
parser->nsamples = 0; parser->nsamples = 0;
parser->samplesize = 0; parser->samplesize = 0;
parser->headersize = 0; parser->headersize = 0;
@ -686,6 +701,41 @@ mares_iconhd_parser_create (dc_parser_t **out, dc_context_t *context, const unsi
return DC_STATUS_SUCCESS; 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 static dc_status_t
mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -698,9 +748,9 @@ mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime
// Pointer to the header data. // Pointer to the header data.
const unsigned char *p = abstract->data; const unsigned char *p = abstract->data;
if (!ISGENIUS(parser->model)) { if (parser->model != GENIUS && parser->model != HORIZON) {
p += abstract->size - parser->headersize; p += abstract->size - parser->headersize;
if (!ISSMART(parser->model)) { if (parser->model != SMART && parser->model != SMARTAPNEA && parser->model != SMARTAIR) {
p += 4; p += 4;
} }
} }
@ -709,7 +759,7 @@ mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime
p += parser->layout->datetime; p += parser->layout->datetime;
if (datetime) { if (datetime) {
if (ISGENIUS(parser->model)) { if (parser->model == GENIUS || parser->model == HORIZON) {
unsigned int timestamp = array_uint32_le (p); unsigned int timestamp = array_uint32_le (p);
datetime->hour = (timestamp ) & 0x1F; datetime->hour = (timestamp ) & 0x1F;
datetime->minute = (timestamp >> 5) & 0x3F; datetime->minute = (timestamp >> 5) & 0x3F;
@ -744,9 +794,9 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
// Pointer to the header data. // Pointer to the header data.
const unsigned char *p = abstract->data; const unsigned char *p = abstract->data;
if (!ISGENIUS(parser->model)) { if (parser->model != GENIUS && parser->model != HORIZON) {
p += abstract->size - parser->headersize; p += abstract->size - parser->headersize;
if (!ISSMART(parser->model)) { if (parser->model != SMART && parser->model != SMARTAPNEA && parser->model != SMARTAIR) {
p += 4; p += 4;
} }
} }
@ -757,7 +807,7 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
extra = 8; extra = 8;
} }
unsigned int metric = ISGENIUS(parser->model) ? unsigned int metric = (parser->model == GENIUS || parser->model == HORIZON) ?
p[0x34 + extra] : parser->settings & 0x0100; p[0x34 + extra] : parser->settings & 0x0100;
dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
@ -770,7 +820,7 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
if (parser->layout->divetime != UNSUPPORTED) { if (parser->layout->divetime != UNSUPPORTED) {
*((unsigned int *) value) = array_uint16_le (p + parser->layout->divetime); *((unsigned int *) value) = array_uint16_le (p + parser->layout->divetime);
} else { } else {
*((unsigned int *) value) = parser->nsamples * parser->interval / 1000 - parser->surftime; *((unsigned int *) value) = parser->nsamples * parser->interval - parser->surftime;
} }
break; break;
case DC_FIELD_MAXDEPTH: case DC_FIELD_MAXDEPTH:
@ -780,7 +830,6 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
*((unsigned int *) value) = parser->ngasmixes; *((unsigned int *) value) = parser->ngasmixes;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0; gasmix->oxygen = parser->gasmix[flags].oxygen / 100.0;
gasmix->helium = parser->gasmix[flags].helium / 100.0; gasmix->helium = parser->gasmix[flags].helium / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -808,13 +857,12 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
} else { } else {
tank->gasmix = DC_GASMIX_UNKNOWN; tank->gasmix = DC_GASMIX_UNKNOWN;
} }
tank->usage = DC_USAGE_NONE;
break; break;
case DC_FIELD_ATMOSPHERIC: case DC_FIELD_ATMOSPHERIC:
*((double *) value) = array_uint16_le (p + parser->layout->atmospheric) / (1000.0 * parser->layout->atmospheric_divisor); *((double *) value) = array_uint16_le (p + parser->layout->atmospheric) / (1000.0 * parser->layout->atmospheric_divisor);
break; break;
case DC_FIELD_SALINITY: case DC_FIELD_SALINITY:
if (ISGENIUS(parser->model)) { if (parser->model == GENIUS || parser->model == HORIZON) {
unsigned int salinity = (parser->settings >> 5) & 0x03; unsigned int salinity = (parser->settings >> 5) & 0x03;
switch (salinity) { switch (salinity) {
case WATER_FRESH: case WATER_FRESH:
@ -856,7 +904,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; *((double *) value) = (signed short) array_uint16_le (p + parser->layout->temperature_max) / 10.0;
break; break;
case DC_FIELD_DIVEMODE: case DC_FIELD_DIVEMODE:
if (ISGENIUS(parser->model)) { if (parser->model == GENIUS || parser->model == HORIZON) {
switch (parser->mode) { switch (parser->mode) {
case GENIUS_AIR: case GENIUS_AIR:
case GENIUS_NITROX_SINGLE: case GENIUS_NITROX_SINGLE:
@ -904,16 +952,64 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi
static dc_status_t static dc_status_t
mares_iconhd_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata) 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; 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; 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 // Previous gas mix - initialize with impossible value
unsigned int gasmix_previous = 0xFFFFFFFF; unsigned int gasmix_previous = 0xFFFFFFFF;
unsigned int offset = 4; unsigned int offset = 4;
unsigned int marker = 0; 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 time = 0;
unsigned int nsamples = 0; unsigned int nsamples = 0;
while (nsamples < parser->nsamples) { while (nsamples < parser->nsamples) {
@ -925,73 +1021,118 @@ mares_iconhd_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void
unsigned int surftime = array_uint16_le (data + offset + 4); unsigned int surftime = array_uint16_le (data + offset + 4);
// Surface Time (seconds). // Surface Time (seconds).
time += surftime * 1000; time += surftime;
sample.time = time; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Surface Depth (0 m). // Surface Depth (0 m).
sample.depth = 0.0; sample.depth = 0.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
offset += parser->samplesize; offset += parser->samplesize;
nsamples++; nsamples++;
unsigned int count = divetime * parser->samplerate; for (unsigned int i = 0; i < divetime; ++i) {
for (unsigned int i = 0; i < count; ++i) {
// Time (seconds). // Time (seconds).
time += parser->interval; time += parser->interval;
sample.time = time; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/10 m). // Depth (1/10 m).
unsigned int depth = array_uint16_le (data + offset); unsigned int depth = array_uint16_le (data + offset);
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
offset += 2; offset += 2 * parser->samplerate;
} }
} else if (parser->mode == ICONHD_FREEDIVE) { } else if (parser->model != GENIUS && parser->model != HORIZON && parser->mode == ICONHD_FREEDIVE) {
unsigned int maxdepth = array_uint16_le (data + offset + 0); unsigned int maxdepth = array_uint16_le (data + offset + 0);
unsigned int divetime = array_uint16_le (data + offset + 2); unsigned int divetime = array_uint16_le (data + offset + 2);
unsigned int surftime = array_uint16_le (data + offset + 4); unsigned int surftime = array_uint16_le (data + offset + 4);
// Surface Time (seconds). // Surface Time (seconds).
time += surftime * 1000; time += surftime;
sample.time = time; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Surface Depth (0 m). // Surface Depth (0 m).
sample.depth = 0.0; sample.depth = 0.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Dive Time (seconds). // Dive Time (seconds).
time += divetime * 1000; time += divetime;
sample.time = time; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Maximum Depth (1/10 m). // Maximum Depth (1/10 m).
sample.depth = maxdepth / 10.0; sample.depth = maxdepth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
offset += parser->samplesize; offset += parser->samplesize;
nsamples++; nsamples++;
} else { } else {
unsigned int depth = array_uint16_le (data + offset + 0); unsigned int depth = 0, temperature = 0;
unsigned int temperature = array_uint16_le (data + offset + 2) & 0x0FFF; unsigned int gasmix = 0, alarms = 0;
unsigned int gasmix = (data[offset + 3] & 0xF0) >> 4; 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;
}
// Time (seconds). // Time (seconds).
time += parser->interval; time += parser->interval;
sample.time = time; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/10 m). // Depth (1/10 m).
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Temperature (1/10 °C). // Temperature (1/10 °C).
sample.temperature = temperature / 10.0; sample.temperature = temperature / 10.0;
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
// Current gas mix // Current gas mix
if (parser->ngasmixes > 0) { if (parser->ngasmixes > 0) {
@ -1001,264 +1142,95 @@ mares_iconhd_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void
} }
if (gasmix != gasmix_previous) { if (gasmix != gasmix_previous) {
sample.gasmix = gasmix; sample.gasmix = gasmix;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix_previous = gasmix; gasmix_previous = gasmix;
} }
} }
// 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; offset += parser->samplesize;
nsamples++; nsamples++;
// Some extra data. // Some extra data.
if (parser->layout->tanks != UNSUPPORTED && (nsamples % 4) == 0) { 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). // Pressure (1/100 bar).
unsigned int pressure = array_uint16_le(data + offset + marker + 0); unsigned int pressure = array_uint16_le(data + offset + marker + 0);
if (gasmix < parser->ntanks) { if (gasmix < parser->ntanks) {
sample.pressure.tank = gasmix; sample.pressure.tank = gasmix;
sample.pressure.value = pressure / 100.0; 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) { } else if (pressure != 0) {
WARNING (abstract->context, "Invalid tank with non-zero pressure."); WARNING (abstract->context, "Invalid tank with non-zero pressure.");
} }
offset += 8; offset += (parser->model == GENIUS || parser->model == HORIZON) ? AIRS_SIZE : 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_DATAFORMAT;
}
offset += DEND_SIZE;
}
return DC_STATUS_SUCCESS; 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;
}
// 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);
}
}

View File

@ -35,7 +35,7 @@ dc_status_t
mares_nemo_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); mares_nemo_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
mares_nemo_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model); mares_nemo_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -59,6 +59,7 @@ struct mares_nemo_parser_t {
unsigned int extra; 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_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_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); static dc_status_t mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -66,6 +67,7 @@ static dc_status_t mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_
static const dc_parser_vtable_t mares_nemo_parser_vtable = { static const dc_parser_vtable_t mares_nemo_parser_vtable = {
sizeof(mares_nemo_parser_t), sizeof(mares_nemo_parser_t),
DC_FAMILY_MARES_NEMO, DC_FAMILY_MARES_NEMO,
mares_nemo_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -77,16 +79,15 @@ static const dc_parser_vtable_t mares_nemo_parser_vtable = {
dc_status_t dc_status_t
mares_nemo_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model) mares_nemo_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
mares_nemo_parser_t *parser = NULL; mares_nemo_parser_t *parser = NULL;
if (out == NULL) if (out == NULL)
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (mares_nemo_parser_t *) dc_parser_allocate (context, &mares_nemo_parser_vtable, data, size); parser = (mares_nemo_parser_t *) dc_parser_allocate (context, &mares_nemo_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -97,42 +98,70 @@ mares_nemo_parser_create (dc_parser_t **out, dc_context_t *context, const unsign
if (model == NEMOWIDE || model == NEMOAIR || model == PUCK || model == PUCKAIR) if (model == NEMOWIDE || model == NEMOAIR || model == PUCK || model == PUCKAIR)
freedive = GAUGE; freedive = GAUGE;
if (size < 2 + 3) { // Set the default values.
status = DC_STATUS_DATAFORMAT; parser->model = model;
goto error_free; 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;
unsigned int length = array_uint16_le (data); unsigned int length = array_uint16_le (data);
if (length > size) { if (length > size)
status = DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
goto error_free;
}
unsigned int extra = 0; unsigned int extra = 0;
const unsigned char marker[3] = {0xAA, 0xBB, 0xCC}; const unsigned char marker[3] = {0xAA, 0xBB, 0xCC};
if (memcmp (data + length - 3, marker, sizeof (marker)) == 0) { if (memcmp (data + length - 3, marker, sizeof (marker)) == 0) {
if (model == PUCKAIR) if (parser->model == PUCKAIR)
extra = 7; extra = 7;
else else
extra = 12; extra = 12;
} }
if (length < 2 + extra + 3) { if (length < 2 + extra + 3)
status = DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
goto error_free;
}
unsigned int mode = data[length - extra - 1]; unsigned int mode = data[length - extra - 1];
unsigned int header_size = 53; unsigned int header_size = 53;
unsigned int sample_size = 2; unsigned int sample_size = 2;
if (extra) { if (extra) {
if (model == PUCKAIR) if (parser->model == PUCKAIR)
sample_size = 3; sample_size = 3;
else else
sample_size = 5; sample_size = 5;
} }
if (mode == freedive) { if (mode == parser->freedive) {
header_size = 28; header_size = 28;
sample_size = 6; sample_size = 6;
} }
@ -140,14 +169,12 @@ mares_nemo_parser_create (dc_parser_t **out, dc_context_t *context, const unsign
unsigned int nsamples = array_uint16_le (data + length - extra - 3); unsigned int nsamples = array_uint16_le (data + length - extra - 3);
unsigned int nbytes = 2 + nsamples * sample_size + header_size + extra; unsigned int nbytes = 2 + nsamples * sample_size + header_size + extra;
if (length != nbytes) { if (length != nbytes)
status = DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
goto error_free;
}
// Set the default values. // Store the new state.
parser->model = model; parser->base.data = data;
parser->freedive = freedive; parser->base.size = size;
parser->mode = mode; parser->mode = mode;
parser->length = length; parser->length = length;
parser->sample_count = nsamples; parser->sample_count = nsamples;
@ -155,13 +182,7 @@ mares_nemo_parser_create (dc_parser_t **out, dc_context_t *context, const unsign
parser->header = header_size; parser->header = header_size;
parser->extra = extra; parser->extra = extra;
*out = (dc_parser_t*) parser;
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
error_free:
dc_parser_deallocate ((dc_parser_t *) parser);
return status;
} }
@ -230,7 +251,6 @@ mares_nemo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
} }
gasmix->helium = 0.0; gasmix->helium = 0.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
gasmix->usage = DC_USAGE_NONE;
break; break;
case DC_FIELD_TANK_COUNT: case DC_FIELD_TANK_COUNT:
if (parser->extra) if (parser->extra)
@ -270,7 +290,6 @@ mares_nemo_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsign
} else { } else {
tank->gasmix = DC_GASMIX_UNKNOWN; tank->gasmix = DC_GASMIX_UNKNOWN;
} }
tank->usage = DC_USAGE_NONE;
break; break;
case DC_FIELD_TEMPERATURE_MINIMUM: case DC_FIELD_TEMPERATURE_MINIMUM:
*((double *) value) = (signed char) p[53 - 11]; *((double *) value) = (signed char) p[53 - 11];
@ -363,17 +382,17 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
// Time (seconds). // Time (seconds).
time += 20; time += 20;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/10 m). // Depth (1/10 m).
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Gas change. // Gas change.
if (gasmix != gasmix_previous) { if (gasmix != gasmix_previous) {
sample.gasmix = gasmix; sample.gasmix = gasmix;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix_previous = gasmix; gasmix_previous = gasmix;
} }
@ -383,7 +402,7 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
sample.event.time = 0; sample.event.time = 0;
sample.event.flags = 0; sample.event.flags = 0;
sample.event.value = ascent; sample.event.value = ascent;
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
} }
// Deco violation // Deco violation
@ -392,7 +411,7 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
sample.event.time = 0; sample.event.time = 0;
sample.event.flags = 0; sample.event.flags = 0;
sample.event.value = 0; sample.event.value = 0;
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
} }
// Deco stop // Deco stop
@ -403,21 +422,20 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
} }
sample.deco.time = 0; sample.deco.time = 0;
sample.deco.depth = 0.0; sample.deco.depth = 0.0;
sample.deco.tts = 0; if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
// Pressure (1 bar). // Pressure (1 bar).
if (parser->sample_size == 3) { if (parser->sample_size == 3) {
sample.pressure.tank = 0; sample.pressure.tank = 0;
sample.pressure.value = data[idx + 2]; 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) { } else if (parser->sample_size == 5) {
unsigned int type = (time / 20) % 3; unsigned int type = (time / 20) % 3;
if (type == 0) { if (type == 0) {
pressure -= data[idx + 2] * 100; pressure -= data[idx + 2] * 100;
sample.pressure.tank = 0; sample.pressure.tank = 0;
sample.pressure.value = pressure / 100.0; sample.pressure.value = pressure / 100.0;
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata); if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
} }
} }
} }
@ -441,12 +459,12 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
// Surface Time (seconds). // Surface Time (seconds).
time += surftime; time += surftime;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Surface Depth (0 m). // Surface Depth (0 m).
sample.depth = 0.0; sample.depth = 0.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
if (profiles) { if (profiles) {
// Get the freedive sample interval for this model. // Get the freedive sample interval for this model.
@ -482,12 +500,12 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
time += interval; time += interval;
if (time > maxtime) if (time > maxtime)
time = maxtime; // Adjust the last sample. time = maxtime; // Adjust the last sample.
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (1/10 m). // Depth (1/10 m).
sample.depth = depth / 10.0; sample.depth = depth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
} }
// Verify that the number of samples in the profile data // Verify that the number of samples in the profile data
@ -501,12 +519,12 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
} else { } else {
// Dive Time (seconds). // Dive Time (seconds).
time += divetime; time += divetime;
sample.time = time * 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). // Maximum Depth (1/10 m).
sample.depth = maxdepth / 10.0; sample.depth = maxdepth / 10.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
} }
} }
} }

View File

@ -35,7 +35,7 @@ dc_status_t
mclean_extreme_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); mclean_extreme_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
mclean_extreme_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size); mclean_extreme_parser_create (dc_parser_t **parser, dc_context_t *context);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -58,6 +58,7 @@ struct mclean_extreme_parser_t {
unsigned int gasmix[NGASMIXES]; 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_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_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); static dc_status_t mclean_extreme_parser_samples_foreach(dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -65,6 +66,7 @@ static dc_status_t mclean_extreme_parser_samples_foreach(dc_parser_t *abstract,
static const dc_parser_vtable_t mclean_extreme_parser_vtable = { static const dc_parser_vtable_t mclean_extreme_parser_vtable = {
sizeof(mclean_extreme_parser_t), sizeof(mclean_extreme_parser_t),
DC_FAMILY_MCLEAN_EXTREME, DC_FAMILY_MCLEAN_EXTREME,
mclean_extreme_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -75,7 +77,7 @@ static const dc_parser_vtable_t mclean_extreme_parser_vtable = {
}; };
dc_status_t dc_status_t
mclean_extreme_parser_create(dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size) mclean_extreme_parser_create(dc_parser_t **out, dc_context_t *context)
{ {
mclean_extreme_parser_t *parser = NULL; mclean_extreme_parser_t *parser = NULL;
@ -84,7 +86,7 @@ mclean_extreme_parser_create(dc_parser_t **out, dc_context_t *context, const uns
} }
// Allocate memory. // Allocate memory.
parser = (mclean_extreme_parser_t *)dc_parser_allocate(context, &mclean_extreme_parser_vtable, data, size); parser = (mclean_extreme_parser_t *)dc_parser_allocate(context, &mclean_extreme_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR(context, "Failed to allocate memory."); ERROR(context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -102,6 +104,21 @@ mclean_extreme_parser_create(dc_parser_t **out, dc_context_t *context, const uns
return DC_STATUS_SUCCESS; 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 static dc_status_t
mclean_extreme_parser_get_datetime(dc_parser_t *abstract, dc_datetime_t *datetime) mclean_extreme_parser_get_datetime(dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -204,7 +221,6 @@ mclean_extreme_parser_get_field(dc_parser_t *abstract, dc_field_type_t type, uns
*((unsigned int *)value) = parser->ngasmixes; *((unsigned int *)value) = parser->ngasmixes;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = 0.01 * abstract->data[0x0001 + 1 + 2 * parser->gasmix[flags]]; 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->oxygen = 0.01 * abstract->data[0x0001 + 0 + 2 * parser->gasmix[flags]];
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -253,14 +269,14 @@ mclean_extreme_parser_samples_foreach(dc_parser_t *abstract, dc_sample_callback_
const unsigned int setpoint = abstract->data[0x0013 + sp_index]; const unsigned int setpoint = abstract->data[0x0013 + sp_index];
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback(DC_SAMPLE_TIME, &sample, userdata); if (callback) callback(DC_SAMPLE_TIME, sample, userdata);
sample.depth = 0.1 * depth; sample.depth = 0.1 * depth;
if (callback) callback(DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback(DC_SAMPLE_DEPTH, sample, userdata);
sample.temperature = temperature; sample.temperature = temperature;
if (callback) callback(DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback(DC_SAMPLE_TEMPERATURE, sample, userdata);
if (gasmix_id != gasmix_previous) { if (gasmix_id != gasmix_previous) {
// Find the gasmix in the list. // Find the gasmix in the list.
@ -282,13 +298,13 @@ mclean_extreme_parser_samples_foreach(dc_parser_t *abstract, dc_sample_callback_
} }
sample.gasmix = idx; sample.gasmix = idx;
if (callback) callback(DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback(DC_SAMPLE_GASMIX, sample, userdata);
gasmix_previous = gasmix_id; gasmix_previous = gasmix_id;
} }
if (ccr) { if (ccr) {
sample.setpoint = 0.01 * setpoint; sample.setpoint = 0.01 * setpoint;
if (callback) callback(DC_SAMPLE_SETPOINT, &sample, userdata); if (callback) callback(DC_SAMPLE_SETPOINT, sample, userdata);
} }
offset += SZ_SAMPLE; offset += SZ_SAMPLE;

View File

@ -86,8 +86,6 @@ static const oceanic_common_device_vtable_t oceanic_atom2_device_vtable = {
NULL, /* timesync */ NULL, /* timesync */
oceanic_atom2_device_close /* close */ oceanic_atom2_device_close /* close */
}, },
oceanic_common_device_devinfo,
oceanic_common_device_pointers,
oceanic_common_device_logbook, oceanic_common_device_logbook,
oceanic_common_device_profile, oceanic_common_device_profile,
}; };
@ -100,11 +98,10 @@ static const oceanic_common_layout_t aeris_f10_layout = {
0x0100, /* rb_logbook_begin */ 0x0100, /* rb_logbook_begin */
0x0D80, /* rb_logbook_end */ 0x0D80, /* rb_logbook_end */
32, /* rb_logbook_entry_size */ 32, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0D80, /* rb_profile_begin */ 0x0D80, /* rb_profile_begin */
0x10000, /* rb_profile_end */ 0x10000, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
3, /* pt_mode_logbook */ 2, /* pt_mode_logbook */
0, /* pt_mode_serial */ 0, /* pt_mode_serial */
}; };
@ -116,11 +113,10 @@ static const oceanic_common_layout_t aeris_f11_layout = {
0x0100, /* rb_logbook_begin */ 0x0100, /* rb_logbook_begin */
0x0D80, /* rb_logbook_end */ 0x0D80, /* rb_logbook_end */
32, /* rb_logbook_entry_size */ 32, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0D80, /* rb_profile_begin */ 0x0D80, /* rb_profile_begin */
0x20000, /* rb_profile_end */ 0x20000, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
2, /* pt_mode_logbook */ 3, /* pt_mode_logbook */
0, /* pt_mode_serial */ 0, /* pt_mode_serial */
}; };
@ -132,7 +128,6 @@ static const oceanic_common_layout_t oceanic_default_layout = {
0x0240, /* rb_logbook_begin */ 0x0240, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */ 0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */ 0x0A40, /* rb_profile_begin */
0x10000, /* rb_profile_end */ 0x10000, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -148,7 +143,6 @@ static const oceanic_common_layout_t oceanic_atom1_layout = {
0x0240, /* rb_logbook_begin */ 0x0240, /* rb_logbook_begin */
0x0440, /* rb_logbook_end */ 0x0440, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0440, /* rb_profile_begin */ 0x0440, /* rb_profile_begin */
0x8000, /* rb_profile_end */ 0x8000, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -164,7 +158,6 @@ static const oceanic_common_layout_t oceanic_atom2a_layout = {
0x0240, /* rb_logbook_begin */ 0x0240, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */ 0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */ 0x0A40, /* rb_profile_begin */
0xFE00, /* rb_profile_end */ 0xFE00, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -180,7 +173,6 @@ static const oceanic_common_layout_t oceanic_atom2b_layout = {
0x0240, /* rb_logbook_begin */ 0x0240, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */ 0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */ 0x0A40, /* rb_profile_begin */
0xFE00, /* rb_profile_end */ 0xFE00, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -196,7 +188,6 @@ static const oceanic_common_layout_t oceanic_atom2c_layout = {
0x0240, /* rb_logbook_begin */ 0x0240, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */ 0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */ 0x0A40, /* rb_profile_begin */
0xFFF0, /* rb_profile_end */ 0xFFF0, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -212,7 +203,6 @@ static const oceanic_common_layout_t sherwood_wisdom_layout = {
0x03D0, /* rb_logbook_begin */ 0x03D0, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */ 0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */ 0x0A40, /* rb_profile_begin */
0xFE00, /* rb_profile_end */ 0xFE00, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -228,7 +218,6 @@ static const oceanic_common_layout_t oceanic_proplus3_layout = {
0x03E0, /* rb_logbook_begin */ 0x03E0, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */ 0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */ 0x0A40, /* rb_profile_begin */
0xFE00, /* rb_profile_end */ 0xFE00, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -244,7 +233,6 @@ static const oceanic_common_layout_t tusa_zenair_layout = {
0x0240, /* rb_logbook_begin */ 0x0240, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */ 0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */ 0x0A40, /* rb_profile_begin */
0xFE00, /* rb_profile_end */ 0xFE00, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -260,7 +248,6 @@ static const oceanic_common_layout_t oceanic_oc1_layout = {
0x0240, /* rb_logbook_begin */ 0x0240, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */ 0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */ 0x0A40, /* rb_profile_begin */
0x1FE00, /* rb_profile_end */ 0x1FE00, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -276,7 +263,6 @@ static const oceanic_common_layout_t oceanic_oci_layout = {
0x10C0, /* rb_logbook_begin */ 0x10C0, /* rb_logbook_begin */
0x1400, /* rb_logbook_end */ 0x1400, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x1400, /* rb_profile_begin */ 0x1400, /* rb_profile_begin */
0x1FE00, /* rb_profile_end */ 0x1FE00, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -292,7 +278,6 @@ static const oceanic_common_layout_t oceanic_atom3_layout = {
0x0400, /* rb_logbook_begin */ 0x0400, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */ 0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */ 0x0A40, /* rb_profile_begin */
0x1FE00, /* rb_profile_end */ 0x1FE00, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -308,7 +293,6 @@ static const oceanic_common_layout_t oceanic_vt4_layout = {
0x0420, /* rb_logbook_begin */ 0x0420, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */ 0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */ 0x0A40, /* rb_profile_begin */
0x1FE00, /* rb_profile_end */ 0x1FE00, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -324,7 +308,6 @@ static const oceanic_common_layout_t hollis_tx1_layout = {
0x0780, /* rb_logbook_begin */ 0x0780, /* rb_logbook_begin */
0x1000, /* rb_logbook_end */ 0x1000, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x1000, /* rb_profile_begin */ 0x1000, /* rb_profile_begin */
0x40000, /* rb_profile_end */ 0x40000, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -340,7 +323,6 @@ static const oceanic_common_layout_t oceanic_veo1_layout = {
0x0400, /* rb_logbook_begin */ 0x0400, /* rb_logbook_begin */
0x0400, /* rb_logbook_end */ 0x0400, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0400, /* rb_profile_begin */ 0x0400, /* rb_profile_begin */
0x0400, /* rb_profile_end */ 0x0400, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -356,9 +338,8 @@ static const oceanic_common_layout_t oceanic_reactpro_layout = {
0x0400, /* rb_logbook_begin */ 0x0400, /* rb_logbook_begin */
0x0600, /* rb_logbook_end */ 0x0600, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0600, /* rb_profile_begin */ 0x0600, /* rb_profile_begin */
0xFE00, /* rb_profile_end */ 0xFFF0, /* rb_profile_end */
1, /* pt_mode_global */ 1, /* pt_mode_global */
1, /* pt_mode_logbook */ 1, /* pt_mode_logbook */
0, /* pt_mode_serial */ 0, /* pt_mode_serial */
@ -372,7 +353,6 @@ static const oceanic_common_layout_t oceanic_proplusx_layout = {
0x1000, /* rb_logbook_begin */ 0x1000, /* rb_logbook_begin */
0x10000, /* rb_logbook_end */ 0x10000, /* rb_logbook_end */
16, /* rb_logbook_entry_size */ 16, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x40000, /* rb_profile_begin */ 0x40000, /* rb_profile_begin */
0x440000, /* rb_profile_end */ 0x440000, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -388,7 +368,6 @@ static const oceanic_common_layout_t aqualung_i770r_layout = {
0x2000, /* rb_logbook_begin */ 0x2000, /* rb_logbook_begin */
0x10000, /* rb_logbook_end */ 0x10000, /* rb_logbook_end */
16, /* rb_logbook_entry_size */ 16, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x40000, /* rb_profile_begin */ 0x40000, /* rb_profile_begin */
0x640000, /* rb_profile_end */ 0x640000, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -404,7 +383,6 @@ static const oceanic_common_layout_t aeris_a300cs_layout = {
0x0900, /* rb_logbook_begin */ 0x0900, /* rb_logbook_begin */
0x1000, /* rb_logbook_end */ 0x1000, /* rb_logbook_end */
16, /* rb_logbook_entry_size */ 16, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x1000, /* rb_profile_begin */ 0x1000, /* rb_profile_begin */
0x3FE00, /* rb_profile_end */ 0x3FE00, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -420,7 +398,6 @@ static const oceanic_common_layout_t aqualung_i450t_layout = {
0x10C0, /* rb_logbook_begin */ 0x10C0, /* rb_logbook_begin */
0x1400, /* rb_logbook_end */ 0x1400, /* rb_logbook_end */
16, /* rb_logbook_entry_size */ 16, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x1400, /* rb_profile_begin */ 0x1400, /* rb_profile_begin */
0x3FE00, /* rb_profile_end */ 0x3FE00, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -438,14 +415,13 @@ static const oceanic_common_version_t versions[] = {
{"MANTA R\0\0 512K", 0, MANTA, &oceanic_atom2c_layout}, {"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", 0x3349, ATOM2, &oceanic_atom2a_layout},
{"2M ATOM r\0\0 512K", 0, ATOM2, &oceanic_atom2c_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}, {"INSIGHT2 \0\0 512K", 0, INSIGHT2, &oceanic_atom2a_layout},
{"OCEVEO30 \0\0 512K", 0, VEO30, &oceanic_atom2a_layout}, {"OCEVEO30 \0\0 512K", 0, VEO30, &oceanic_atom2a_layout},
{"ATMOSAI R\0\0 512K", 0, ATMOSAI2, &oceanic_atom2a_layout}, {"ATMOSAI R\0\0 512K", 0, ATMOSAI2, &oceanic_atom2a_layout},
{"PROPLUS2 \0\0 512K", 0, PROPLUS21, &oceanic_atom2a_layout}, {"PROPLUS2 \0\0 512K", 0, PROPLUS21, &oceanic_atom2a_layout},
{"OCEGEO20 \0\0 512K", 0, GEO20, &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}, {"AQUAI200 \0\0 512K", 0, I200, &oceanic_atom2a_layout},
{"AQUA200C \0\0 512K", 0, I200C, &oceanic_atom2a_layout}, {"AQUA200C \0\0 512K", 0, I200C, &oceanic_atom2a_layout},

View File

@ -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); oceanic_atom2_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
dc_status_t dc_status_t
oceanic_atom2_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model); oceanic_atom2_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -35,12 +35,6 @@
#define GAUGE 1 #define GAUGE 1
#define FREEDIVE 2 #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 NGASMIXES 6
#define HEADER 1 #define HEADER 1
@ -51,7 +45,6 @@ typedef struct oceanic_atom2_parser_t oceanic_atom2_parser_t;
struct oceanic_atom2_parser_t { struct oceanic_atom2_parser_t {
dc_parser_t base; dc_parser_t base;
unsigned int model; unsigned int model;
unsigned int logbooksize;
unsigned int headersize; unsigned int headersize;
unsigned int footersize; unsigned int footersize;
// Cached fields. // Cached fields.
@ -66,6 +59,7 @@ struct oceanic_atom2_parser_t {
double maxdepth; 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_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_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); static dc_status_t oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -73,6 +67,7 @@ static dc_status_t oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract,
static const dc_parser_vtable_t oceanic_atom2_parser_vtable = { static const dc_parser_vtable_t oceanic_atom2_parser_vtable = {
sizeof(oceanic_atom2_parser_t), sizeof(oceanic_atom2_parser_t),
DC_FAMILY_OCEANIC_ATOM2, DC_FAMILY_OCEANIC_ATOM2,
oceanic_atom2_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -84,7 +79,7 @@ static const dc_parser_vtable_t oceanic_atom2_parser_vtable = {
dc_status_t dc_status_t
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_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{ {
oceanic_atom2_parser_t *parser = NULL; oceanic_atom2_parser_t *parser = NULL;
@ -92,7 +87,7 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, const uns
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (oceanic_atom2_parser_t *) dc_parser_allocate (context, &oceanic_atom2_parser_vtable, data, size); parser = (oceanic_atom2_parser_t *) dc_parser_allocate (context, &oceanic_atom2_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -100,7 +95,6 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, const uns
// Set the default values. // Set the default values.
parser->model = model; parser->model = model;
parser->logbooksize = 0;
parser->headersize = 9 * PAGESIZE / 2; parser->headersize = 9 * PAGESIZE / 2;
parser->footersize = 2 * PAGESIZE / 2; parser->footersize = 2 * PAGESIZE / 2;
if (model == DATAMASK || model == COMPUMASK || if (model == DATAMASK || model == COMPUMASK ||
@ -139,14 +133,6 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, const uns
} else if (model == I550C || model == WISDOM4 || } else if (model == I550C || model == WISDOM4 ||
model == I200CV2) { model == I200CV2) {
parser->headersize = 5 * PAGESIZE / 2; 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; parser->cached = 0;
@ -167,6 +153,28 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, const uns
} }
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 static dc_status_t
oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -186,18 +194,8 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim
if (datetime) { if (datetime) {
// AM/PM bit of the 12-hour clock. // AM/PM bit of the 12-hour clock.
unsigned int pm = p[1] & 0x80; unsigned int pm = p[1] & 0x80;
unsigned int have_ampm = 1;
switch (parser->model) { 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 OC1A:
case OC1B: case OC1B:
case OC1C: case OC1C:
@ -306,11 +304,9 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim
datetime->timezone = DC_TIMEZONE_NONE; datetime->timezone = DC_TIMEZONE_NONE;
// Convert to a 24-hour clock. // Convert to a 24-hour clock.
if (have_ampm) { datetime->hour %= 12;
datetime->hour %= 12; if (pm)
if (pm) datetime->hour += 12;
datetime->hour += 12;
}
/* /*
* Workaround for the year 2010 problem. * Workaround for the year 2010 problem.
@ -385,10 +381,6 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
} else if (parser->model == VEO20 || parser->model == VEO30 || } else if (parser->model == VEO20 || parser->model == VEO30 ||
parser->model == OCS) { parser->model == OCS) {
mode = (data[1] & 0x60) >> 5; 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. // Get the gas mixes.
@ -446,17 +438,6 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
} else if (parser->model == WISDOM4) { } else if (parser->model == WISDOM4) {
o2_offset = header + 4; o2_offset = header + 4;
ngasmixes = 1; 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 { } else {
o2_offset = header + 4; o2_offset = header + 4;
ngasmixes = 3; ngasmixes = 3;
@ -470,10 +451,6 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
for (unsigned int i = 0; i < ngasmixes; ++i) { for (unsigned int i = 0; i < ngasmixes; ++i) {
if (data[o2_offset + i * o2_step]) { if (data[o2_offset + i * o2_step]) {
parser->oxygen[i] = 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 { } else {
parser->oxygen[i] = 21; parser->oxygen[i] = 21;
} }
@ -532,23 +509,13 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
parser->model == F11A || parser->model == F11B || parser->model == F11A || parser->model == F11B ||
parser->model == MUNDIAL2 || parser->model == MUNDIAL3) parser->model == MUNDIAL2 || parser->model == MUNDIAL3)
*((double *) value) = array_uint16_le (data + 4) / 16.0 * FEET; *((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 else
*((double *) value) = (array_uint16_le (data + parser->footer + 4) & 0x0FFF) / 16.0 * FEET; *((double *) value) = (array_uint16_le (data + parser->footer + 4) & 0x0FFF) / 16.0 * FEET;
break; 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: case DC_FIELD_GASMIX_COUNT:
*((unsigned int *) value) = parser->ngasmixes; *((unsigned int *) value) = parser->ngasmixes;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->oxygen = parser->oxygen[flags] / 100.0; gasmix->oxygen = parser->oxygen[flags] / 100.0;
gasmix->helium = parser->helium[flags] / 100.0; gasmix->helium = parser->helium[flags] / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -562,49 +529,23 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
water->type = DC_WATER_SALT; water->type = DC_WATER_SALT;
} }
water->density = 0.0; 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 { } else {
return DC_STATUS_UNSUPPORTED; return DC_STATUS_UNSUPPORTED;
} }
break; break;
case DC_FIELD_DIVEMODE: case DC_FIELD_DIVEMODE:
if (parser->model == DSX) { switch (parser->mode) {
switch (parser->mode) { case NORMAL:
case DSX_OC: *((unsigned int *) value) = DC_DIVEMODE_OC;
case DSX_SIDEMOUNT: break;
*((unsigned int *) value) = DC_DIVEMODE_OC; case GAUGE:
break; *((unsigned int *) value) = DC_DIVEMODE_GAUGE;
case DSX_SIDEGAUGE: break;
case DSX_GAUGE: case FREEDIVE:
*((unsigned int *) value) = DC_DIVEMODE_GAUGE; *((unsigned int *) value) = DC_DIVEMODE_FREEDIVE;
break; break;
case DSX_CC: default:
*((unsigned int *) value) = DC_DIVEMODE_CCR; return DC_STATUS_DATAFORMAT;
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; break;
default: default:
@ -645,7 +586,7 @@ oceanic_atom2_parser_vendor (oceanic_atom2_parser_t *parser, const unsigned char
sample.vendor.type = SAMPLE_VENDOR_OCEANIC_ATOM2; sample.vendor.type = SAMPLE_VENDOR_OCEANIC_ATOM2;
sample.vendor.size = length; sample.vendor.size = length;
sample.vendor.data = data + offset; sample.vendor.data = data + offset;
if (callback) callback (DC_SAMPLE_VENDOR, &sample, userdata); if (callback) callback (DC_SAMPLE_VENDOR, sample, userdata);
offset += length; offset += length;
} }
@ -667,25 +608,30 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
unsigned int extratime = 0; unsigned int extratime = 0;
unsigned int time = 0; unsigned int time = 0;
unsigned int interval = 1000; unsigned int interval = 1;
unsigned int samplerate = 1;
if (parser->mode != FREEDIVE) { if (parser->mode != FREEDIVE) {
if (parser->model == I330R || parser->model == DSX) { unsigned int offset = 0x17;
interval = data[parser->logbooksize + 36] * 1000; if (parser->model == A300CS || parser->model == VTX ||
} else { parser->model == I450T || parser->model == I750TC ||
unsigned int offset = 0x17; parser->model == PROPLUSX || parser->model == I770R ||
if (parser->model == A300CS || parser->model == VTX || parser->model == SAGE || parser->model == BEACON)
parser->model == I450T || parser->model == I750TC || offset = 0x1f;
parser->model == PROPLUSX || parser->model == I770R || const unsigned int intervals[] = {2, 15, 30, 60};
parser->model == SAGE || parser->model == BEACON) unsigned int idx = data[offset] & 0x03;
offset = 0x1f; interval = intervals[idx];
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) { } else if (parser->model == F11A || parser->model == F11B) {
const unsigned int intervals[] = {250, 500, 1000, 2000}; const unsigned int intervals[] = {1, 1, 1, 2};
const unsigned int samplerates[] = {4, 2, 1, 1};
unsigned int idx = data[0x29] & 0x03; unsigned int idx = data[0x29] & 0x03;
interval = intervals[idx]; 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; unsigned int samplesize = PAGESIZE / 2;
@ -704,10 +650,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
parser->model == I750TC || parser->model == PROPLUSX || parser->model == I750TC || parser->model == PROPLUSX ||
parser->model == I770R || parser->model == I470TC || parser->model == I770R || parser->model == I470TC ||
parser->model == SAGE || parser->model == BEACON || parser->model == SAGE || parser->model == BEACON ||
parser->model == GEOAIR || parser->model == I330R) { parser->model == GEOAIR) {
samplesize = PAGESIZE; samplesize = PAGESIZE;
} else if (parser->model == DSX) {
samplesize = 32;
} }
unsigned int have_temperature = 1, have_pressure = 1; unsigned int have_temperature = 1, have_pressure = 1;
@ -722,8 +666,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
parser->model == I200 || parser->model == I100 || parser->model == I200 || parser->model == I100 ||
parser->model == I300C || parser->model == TALIS || parser->model == I300C || parser->model == TALIS ||
parser->model == I200C || parser->model == I200CV2 || parser->model == I200C || parser->model == I200CV2 ||
parser->model == GEO40 || parser->model == VEO40 || parser->model == GEO40 || parser->model == VEO40) {
parser->model == I330R) {
have_pressure = 0; have_pressure = 0;
} }
@ -734,7 +677,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
} }
// Initial tank pressure. // Initial tank pressure.
unsigned int tank = 1; unsigned int tank = 0;
unsigned int pressure = 0; unsigned int pressure = 0;
if (have_pressure) { if (have_pressure) {
unsigned int idx = 2; unsigned int idx = 2;
@ -789,17 +732,17 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
if (sampletype == 0xAA) { if (sampletype == 0xAA) {
if (parser->model == DATAMASK || parser->model == COMPUMASK) { if (parser->model == DATAMASK || parser->model == COMPUMASK) {
// Tank pressure (1 psi) and number // Tank pressure (1 psi) and number
tank = 1; tank = 0;
pressure = (((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF); pressure = (((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF);
} else if (parser->model == A300CS || parser->model == VTX || } else if (parser->model == A300CS || parser->model == VTX ||
parser->model == I750TC || parser->model == SAGE || parser->model == I750TC || parser->model == SAGE ||
parser->model == BEACON) { parser->model == BEACON) {
// Tank pressure (1 psi) and number (one based index) // Tank pressure (1 psi) and number (one based index)
tank = data[offset + 1] & 0x03; tank = (data[offset + 1] & 0x03) - 1;
pressure = ((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF; pressure = ((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF;
} else { } else {
// Tank pressure (2 psi) and number (one based index) // Tank pressure (2 psi) and number (one based index)
tank = data[offset + 1] & 0x03; tank = (data[offset + 1] & 0x03) - 1;
if (parser->model == ATOM2 || parser->model == EPICA || parser->model == EPICB) if (parser->model == ATOM2 || parser->model == EPICA || parser->model == EPICB)
pressure = (((data[offset + 3] << 8) + data[offset + 4]) & 0x0FFF) * 2; pressure = (((data[offset + 3] << 8) + data[offset + 4]) & 0x0FFF) * 2;
else else
@ -809,14 +752,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 surface time is not always a nice multiple of the samplerate.
// The number of inserted surface samples is therefore rounded down // The number of inserted surface samples is therefore rounded down
// to keep the timestamps aligned at multiples of the samplerate. // to keep the timestamps aligned at multiples of the samplerate.
unsigned int surftime = (60 * bcd2dec (data[offset + 1]) + bcd2dec (data[offset + 2])) * 1000; unsigned int surftime = 60 * bcd2dec (data[offset + 1]) + bcd2dec (data[offset + 2]);
unsigned int nsamples = surftime / interval; unsigned int nsamples = surftime / interval;
for (unsigned int i = 0; i < nsamples; ++i) { for (unsigned int i = 0; i < nsamples; ++i) {
// Time // Time
time += interval; time += interval;
sample.time = time; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Vendor specific data // Vendor specific data
if (i == 0) { if (i == 0) {
@ -828,18 +771,25 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
// Depth // Depth
sample.depth = 0.0; sample.depth = 0.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
complete = 1; complete = 1;
} }
extratime += surftime; extratime += surftime;
} else { } else {
// Skip the extra samples.
if ((count % samplerate) != 0) {
offset += samplesize;
count++;
continue;
}
// Time. // Time.
if (parser->model == I450T || parser->model == I470TC) { if (parser->model == I450T || parser->model == I470TC) {
unsigned int minute = bcd2dec(data[offset + 0]); unsigned int minute = bcd2dec(data[offset + 0]);
unsigned int hour = bcd2dec(data[offset + 1] & 0x0F); unsigned int hour = bcd2dec(data[offset + 1] & 0x0F);
unsigned int second = bcd2dec(data[offset + 2]); unsigned int second = bcd2dec(data[offset + 2]);
unsigned int timestamp = ((hour * 3600) + (minute * 60 ) + second) * 1000 + extratime; unsigned int timestamp = (hour * 3600) + (minute * 60 ) + second + extratime;
if (timestamp < time) { if (timestamp < time) {
ERROR (abstract->context, "Timestamp moved backwards."); ERROR (abstract->context, "Timestamp moved backwards.");
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
@ -853,7 +803,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
time += interval; time += interval;
} }
sample.time = time; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Vendor specific data // Vendor specific data
oceanic_atom2_parser_vendor (parser, oceanic_atom2_parser_vendor (parser,
@ -892,8 +842,6 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
parser->model == I770R|| parser->model == SAGE || parser->model == I770R|| parser->model == SAGE ||
parser->model == BEACON) { parser->model == BEACON) {
temperature = data[offset + 11]; temperature = data[offset + 11];
} else if (parser->model == I330R || parser->model == DSX) {
temperature = array_uint16_le(data + offset + 10);
} else { } else {
unsigned int sign; unsigned int sign;
if (parser->model == DG03 || parser->model == PROPLUS3 || if (parser->model == DG03 || parser->model == PROPLUS3 ||
@ -916,12 +864,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
else else
temperature += (data[offset + 7] & 0x0C) >> 2; temperature += (data[offset + 7] & 0x0C) >> 2;
} }
if (parser->model == I330R || parser->model == DSX) { sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
sample.temperature = ((temperature / 10.0) - 32.0) * (5.0 / 9.0); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
} else {
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
}
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
} }
// Tank Pressure (psi) // Tank Pressure (psi)
@ -945,17 +889,11 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
parser->model == PROPLUSX || parser->model == I770R || parser->model == PROPLUSX || parser->model == I770R ||
parser->model == SAGE || parser->model == BEACON) parser->model == SAGE || parser->model == BEACON)
pressure = array_uint16_le (data + offset + 4); pressure = array_uint16_le (data + offset + 4);
else if (parser->model == DSX) { else
pressure = array_uint16_le (data + offset + 14);
tank = (data[offset] & 0xF0) >> 4;
} else {
pressure -= data[offset + 1]; pressure -= data[offset + 1];
} sample.pressure.tank = tank;
if (tank) { sample.pressure.value = pressure * PSI / BAR;
sample.pressure.tank = tank - 1; if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
sample.pressure.value = pressure * PSI / BAR;
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
}
} }
// Depth (1/16 ft) // Depth (1/16 ft)
@ -973,18 +911,12 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
parser->model == I470TC || parser->model == I200CV2 || parser->model == I470TC || parser->model == I200CV2 ||
parser->model == GEOAIR) parser->model == GEOAIR)
depth = (data[offset + 4] + (data[offset + 5] << 8)) & 0x0FFF; 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) else if (parser->model == ATOM1)
depth = data[offset + 3] * 16; depth = data[offset + 3] * 16;
else else
depth = (data[offset + 2] + (data[offset + 3] << 8)) & 0x0FFF; depth = (data[offset + 2] + (data[offset + 3] << 8)) & 0x0FFF;
if (parser->model == I330R || parser->model == DSX) { sample.depth = depth / 16.0 * FEET;
sample.depth = depth / 10.0 * FEET; if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
} else {
sample.depth = depth / 16.0 * FEET;
}
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
// Gas mix // Gas mix
unsigned int have_gasmix = 0; unsigned int have_gasmix = 0;
@ -992,17 +924,14 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
if (parser->model == TX1) { if (parser->model == TX1) {
gasmix = data[offset] & 0x07; gasmix = data[offset] & 0x07;
have_gasmix = 1; have_gasmix = 1;
} else if (parser->model == DSX) {
gasmix = (data[offset] & 0xF0) >> 4;
have_gasmix = 1;
} }
if (have_gasmix && gasmix != gasmix_previous && parser->ngasmixes > 0) { if (have_gasmix && gasmix != gasmix_previous) {
if (gasmix < 1 || gasmix > parser->ngasmixes) { if (gasmix < 1 || gasmix > parser->ngasmixes) {
ERROR (abstract->context, "Invalid gas mix index (%u).", gasmix); ERROR (abstract->context, "Invalid gas mix index (%u).", gasmix);
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
} }
sample.gasmix = gasmix - 1; sample.gasmix = gasmix - 1;
if (callback) callback (DC_SAMPLE_GASMIX, &sample, userdata); if (callback) callback (DC_SAMPLE_GASMIX, sample, userdata);
gasmix_previous = gasmix; gasmix_previous = gasmix;
} }
@ -1026,8 +955,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
have_deco = 1; have_deco = 1;
} else if (parser->model == ATOM31 || parser->model == VISION || } else if (parser->model == ATOM31 || parser->model == VISION ||
parser->model == XPAIR || parser->model == I550 || 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; decostop = (data[offset + 5] & 0xF0) >> 4;
decotime = array_uint16_le(data + offset + 4) & 0x03FF; decotime = array_uint16_le(data + offset + 4) & 0x03FF;
have_deco = 1; have_deco = 1;
@ -1042,32 +970,17 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
decostop = (data[offset + 7] & 0xF0) >> 4; decostop = (data[offset + 7] & 0xF0) >> 4;
decotime = array_uint16_le(data + offset + 6) & 0x0FFF; decotime = array_uint16_le(data + offset + 6) & 0x0FFF;
have_deco = 1; 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 (have_deco) {
if (decostop) { if (decostop) {
sample.deco.type = DC_DECO_DECOSTOP; sample.deco.type = DC_DECO_DECOSTOP;
if (parser->model == I330R || parser->model == DSX) { sample.deco.depth = decostop * 10 * FEET;
sample.deco.depth = decostop * FEET;
} else {
sample.deco.depth = decostop * 10 * FEET;
}
} else { } else {
sample.deco.type = DC_DECO_NDL; sample.deco.type = DC_DECO_NDL;
sample.deco.depth = 0.0; sample.deco.depth = 0.0;
} }
sample.deco.time = decotime * 60; sample.deco.time = decotime * 60;
sample.deco.tts = 0; if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
} }
unsigned int have_rbt = 0; unsigned int have_rbt = 0;
@ -1084,21 +997,13 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
have_rbt = 1; have_rbt = 1;
} else if (parser->model == VISION || parser->model == XPAIR || } else if (parser->model == VISION || parser->model == XPAIR ||
parser->model == I550 || parser->model == I550C || parser->model == I550 || parser->model == I550C ||
parser->model == WISDOM4 || parser->model == PROPLUS4 || parser->model == WISDOM4) {
parser->model == ATMOSAI2) {
rbt = array_uint16_le(data + offset + 6) & 0x03FF; rbt = array_uint16_le(data + offset + 6) & 0x03FF;
have_rbt = 1; have_rbt = 1;
} }
if (have_rbt) { if (have_rbt) {
sample.rbt = 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 // Bookmarks
@ -1113,7 +1018,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
sample.event.time = 0; sample.event.time = 0;
sample.event.flags = 0; sample.event.flags = 0;
sample.event.value = 0; sample.event.value = 0;
if (callback) callback (DC_SAMPLE_EVENT, &sample, userdata); if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
} }
count++; count++;

View File

@ -32,62 +32,72 @@
#define VTABLE(abstract) ((const oceanic_common_device_vtable_t *) abstract->vtable) #define VTABLE(abstract) ((const oceanic_common_device_vtable_t *) abstract->vtable)
#define RB_LOGBOOK_DISTANCE(a,b,l,m) ringbuffer_distance (a, b, m, l->rb_logbook_begin, l->rb_logbook_end) #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_PROFILE_DISTANCE(a,b,l,m) ringbuffer_distance (a, b, m, l->rb_profile_begin, l->rb_profile_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 INVALID 0 #define INVALID 0
static dc_status_t static unsigned int
oceanic_common_device_get_profile (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int *begin, unsigned int *end) get_profile_first (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int pagesize)
{ {
assert (layout != NULL); unsigned int value;
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) { if (layout->pt_mode_logbook == 0) {
first = array_uint16_le (data + 5); value = array_uint16_le (data + 5);
last = array_uint16_le (data + 6) >> 4;
} else if (layout->pt_mode_logbook == 1) { } else if (layout->pt_mode_logbook == 1) {
first = array_uint16_le (data + 4); value = array_uint16_le (data + 4);
last = array_uint16_le (data + 6); } else if (layout->pt_mode_logbook == 3) {
} else if (layout->pt_mode_logbook == 2 || layout->pt_mode_logbook == 3) { value = array_uint16_le (data + 16);
first = array_uint16_le (data + 16); } else {
last = array_uint16_le (data + 18); return array_uint16_le (data + 16);
} else if (layout->pt_mode_logbook == 4) {
first = array_uint32_le (data + 8);
last = array_uint32_le (data + 12);
} }
// Convert pages to bytes. unsigned int npages = (layout->memsize - layout->highmem) / pagesize;
if (layout->pt_mode_logbook < 3) { if (npages > 0x4000) {
unsigned int npages = (layout->memsize - layout->highmem) / pagesize; value &= 0x7FFF;
if (npages > 0x4000) { } else if (npages > 0x2000) {
first &= 0x7FFF; value &= 0x3FFF;
last &= 0x7FFF; } else if (npages > 0x1000) {
} else if (npages > 0x2000) { value &= 0x1FFF;
first &= 0x3FFF; } else {
last &= 0x3FFF; value &= 0x0FFF;
} else if (npages > 0x1000) {
first &= 0x1FFF;
last &= 0x1FFF;
} else {
first &= 0x0FFF;
last &= 0x0FFF;
}
first *= pagesize;
last *= pagesize;
} }
*begin = layout->highmem + first; return layout->highmem + value * pagesize;
*end = layout->highmem + last + (layout->pt_mode_logbook < 4 ? pagesize : 0); }
return DC_STATUS_SUCCESS;
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;
} }
@ -196,11 +206,11 @@ oceanic_common_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
} }
// Read the device info. // Emit a vendor event.
status = VTABLE(abstract)->devinfo (abstract, NULL); dc_event_vendor_t vendor;
if (status != DC_STATUS_SUCCESS) { vendor.data = device->version;
return status; vendor.size = sizeof (device->version);
} device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
// Download the memory dump. // Download the memory dump.
status = device_dump_read (abstract, 0, dc_buffer_get_data (buffer), status = device_dump_read (abstract, 0, dc_buffer_get_data (buffer),
@ -209,43 +219,8 @@ oceanic_common_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
return status; 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. // Emit a device info event.
unsigned char *id = dc_buffer_get_data (buffer) + layout->cf_devinfo;
dc_event_devinfo_t devinfo; dc_event_devinfo_t devinfo;
devinfo.model = array_uint16_be (id + 8); devinfo.model = array_uint16_be (id + 8);
devinfo.firmware = device->firmware; devinfo.firmware = device->firmware;
@ -265,51 +240,7 @@ oceanic_common_device_devinfo (dc_device_t *abstract, dc_event_progress_t *progr
dc_status_t dc_status_t
oceanic_common_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress, oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook)
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; oceanic_common_device_t *device = (oceanic_common_device_t *) abstract;
dc_status_t rc = DC_STATUS_SUCCESS; dc_status_t rc = DC_STATUS_SUCCESS;
@ -325,30 +256,37 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr
if (!dc_buffer_clear (logbook)) if (!dc_buffer_clear (logbook))
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
// Validate the logbook pointers. // For devices without a logbook ringbuffer, downloading dives isn't
unsigned int rb_logbook_begin = begin; // possible. This is not considered a fatal error, but handled as if there
unsigned int rb_logbook_end = end; // are no dives present.
if (rb_logbook_begin < layout->rb_logbook_begin || if (layout->rb_logbook_begin == layout->rb_logbook_end) {
rb_logbook_begin > layout->rb_logbook_end) return DC_STATUS_SUCCESS;
{
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;
} }
if (rb_logbook_end < layout->rb_logbook_begin ||
rb_logbook_end > layout->rb_logbook_end) // 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)
{ {
ERROR (abstract->context, "Invalid logbook end pointer detected (0x%04x).", rb_logbook_end); ERROR (abstract->context, "Invalid logbook end pointer detected (0x%04x).", rb_logbook_last);
if (layout->rb_logbook_direction != 0) { return DC_STATUS_DATAFORMAT;
return DC_STATUS_DATAFORMAT; }
}
// Fall back to downloading the entire logbook ringbuffer as // Calculate the end pointer.
// workaround for an invalid logbook end pointer! unsigned int rb_logbook_end = 0;
rb_logbook_end = rb_logbook_begin; 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;
} }
// Calculate the number of bytes. // Calculate the number of bytes.
@ -357,9 +295,21 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr
// full ringbuffer. We always consider the ringbuffer full in that // full ringbuffer. We always consider the ringbuffer full in that
// case, because an empty ringbuffer can be detected by inspecting // case, because an empty ringbuffer can be detected by inspecting
// the logbook entries once they are downloaded. // the logbook entries once they are downloaded.
unsigned int rb_logbook_size = RB_LOGBOOK_DISTANCE (rb_logbook_begin, rb_logbook_end, layout, DC_RINGBUFFER_FULL); 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);
}
// Update and emit a progress event. // 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; progress->maximum -= (layout->rb_logbook_end - layout->rb_logbook_begin) - rb_logbook_size;
device_event_emit (abstract, DC_EVENT_PROGRESS, progress); device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
@ -377,11 +327,7 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr
// Create the ringbuffer stream. // Create the ringbuffer stream.
dc_rbstream_t *rbstream = NULL; dc_rbstream_t *rbstream = NULL;
rc = dc_rbstream_new (&rbstream, abstract, rc = dc_rbstream_new (&rbstream, abstract, PAGESIZE, PAGESIZE * device->multipage, layout->rb_logbook_begin, layout->rb_logbook_end, rb_logbook_end);
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) { if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream."); ERROR (abstract->context, "Failed to create the ringbuffer stream.");
return rc; return rc;
@ -457,6 +403,9 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
const oceanic_common_layout_t *layout = device->layout; 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. // Cache the logbook pointer and size.
const unsigned char *logbooks = dc_buffer_get_data (logbook); const unsigned char *logbooks = dc_buffer_get_data (logbook);
unsigned int rb_logbook_size = dc_buffer_get_size (logbook); unsigned int rb_logbook_size = dc_buffer_get_size (logbook);
@ -464,7 +413,6 @@ 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 // 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 pointer and calculate the total amount of bytes in the
// profile ringbuffer. // profile ringbuffer.
unsigned int rb_profile_begin = INVALID;
unsigned int rb_profile_end = INVALID; unsigned int rb_profile_end = INVALID;
unsigned int rb_profile_size = 0; unsigned int rb_profile_size = 0;
@ -486,20 +434,22 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
} }
// Get the profile pointers. // Get the profile pointers.
unsigned int rb_entry_begin = 0, rb_entry_end = 0; unsigned int rb_entry_first = get_profile_first (logbooks + entry, layout, pagesize);
oceanic_common_device_get_profile (logbooks + entry, layout, &rb_entry_begin, &rb_entry_end); unsigned int rb_entry_last = get_profile_last (logbooks + entry, layout, pagesize);
if (rb_entry_begin < layout->rb_profile_begin || if (rb_entry_first < layout->rb_profile_begin ||
rb_entry_begin > layout->rb_profile_end || rb_entry_first >= layout->rb_profile_end ||
rb_entry_end < layout->rb_profile_begin || rb_entry_last < layout->rb_profile_begin ||
rb_entry_end > layout->rb_profile_end) rb_entry_last >= layout->rb_profile_end)
{ {
ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).", ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).",
rb_entry_begin, rb_entry_end); rb_entry_first, rb_entry_last);
status = DC_STATUS_DATAFORMAT; status = DC_STATUS_DATAFORMAT;
continue; continue;
} }
DEBUG (abstract->context, "Entry: %08x %08x", rb_entry_begin, rb_entry_end); // 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;
// Take the end pointer of the most recent logbook entry as the // Take the end pointer of the most recent logbook entry as the
// end of profile pointer. // end of profile pointer.
@ -507,13 +457,11 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
rb_profile_end = previous = rb_entry_end; 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. // Skip gaps between the profiles.
unsigned int gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout, DC_RINGBUFFER_EMPTY); unsigned int gap = 0;
if (gap) { if (rb_entry_end != previous) {
WARNING (abstract->context, "Profiles are not continuous (%u bytes).", gap); WARNING (abstract->context, "Profiles are not continuous.");
gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout);
} }
// Make sure the profile size is valid. // Make sure the profile size is valid.
@ -522,18 +470,13 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
break; break;
} }
// Update the profile begin pointer.
rb_profile_begin = rb_entry_begin;
// Update the total profile size. // Update the total profile size.
rb_profile_size += rb_entry_size + gap; rb_profile_size += rb_entry_size + gap;
remaining -= rb_entry_size + gap; remaining -= rb_entry_size + gap;
previous = rb_entry_begin; previous = rb_entry_first;
} }
DEBUG (abstract->context, "Profile: %08x %08x", rb_profile_begin, rb_profile_end);
// At this point, we know the exact amount of data // At this point, we know the exact amount of data
// that needs to be transfered for the profiles. // that needs to be transfered for the profiles.
progress->maximum -= (layout->rb_profile_end - layout->rb_profile_begin) - rb_profile_size; progress->maximum -= (layout->rb_profile_end - layout->rb_profile_begin) - rb_profile_size;
@ -546,7 +489,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
// Create the ringbuffer stream. // Create the ringbuffer stream.
dc_rbstream_t *rbstream = NULL; 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, DC_RBSTREAM_BACKWARD); rc = dc_rbstream_new (&rbstream, abstract, PAGESIZE, PAGESIZE * device->multipage, layout->rb_profile_begin, layout->rb_profile_end, rb_profile_end);
if (rc != DC_STATUS_SUCCESS) { if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream."); ERROR (abstract->context, "Failed to create the ringbuffer stream.");
return rc; return rc;
@ -581,28 +524,28 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
} }
// Get the profile pointers. // Get the profile pointers.
unsigned int rb_entry_begin = 0, rb_entry_end = 0; unsigned int rb_entry_first = get_profile_first (logbooks + entry, layout, pagesize);
oceanic_common_device_get_profile (logbooks + entry, layout, &rb_entry_begin, &rb_entry_end); unsigned int rb_entry_last = get_profile_last (logbooks + entry, layout, pagesize);
if (rb_entry_begin < layout->rb_profile_begin || if (rb_entry_first < layout->rb_profile_begin ||
rb_entry_begin > layout->rb_profile_end || rb_entry_first >= layout->rb_profile_end ||
rb_entry_end < layout->rb_profile_begin || rb_entry_last < layout->rb_profile_begin ||
rb_entry_end > layout->rb_profile_end) rb_entry_last >= layout->rb_profile_end)
{ {
ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).", ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).",
rb_entry_begin, rb_entry_end); rb_entry_first, rb_entry_last);
status = DC_STATUS_DATAFORMAT; status = DC_STATUS_DATAFORMAT;
continue; continue;
} }
DEBUG (abstract->context, "Entry: %08x %08x", rb_entry_begin, rb_entry_end); // Calculate the end pointer and the number of bytes.
unsigned int rb_entry_end = RB_PROFILE_INCR (rb_entry_last, pagesize, layout);
// Calculate the number of bytes. unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_first, rb_entry_last, layout) + pagesize;
unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_begin, rb_entry_end, layout, DC_RINGBUFFER_FULL);
// Skip gaps between the profiles. // Skip gaps between the profiles.
unsigned int gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout, DC_RINGBUFFER_EMPTY); unsigned int gap = 0;
if (gap) { if (rb_entry_end != previous) {
WARNING (abstract->context, "Profiles are not continuous (%u bytes).", gap); WARNING (abstract->context, "Profiles are not continuous.");
gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout);
} }
// Make sure the profile size is valid. // Make sure the profile size is valid.
@ -623,7 +566,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
} }
remaining -= rb_entry_size + gap; remaining -= rb_entry_size + gap;
previous = rb_entry_begin; previous = rb_entry_first;
// Prepend the logbook entry to the profile data. The memory buffer is // Prepend the logbook entry to the profile data. The memory buffer is
// large enough to store this entry. // large enough to store this entry.
@ -661,7 +604,6 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
dc_status_t dc_status_t
oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata) 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; oceanic_common_device_t *device = (oceanic_common_device_t *) abstract;
assert (device != NULL); assert (device != NULL);
@ -669,37 +611,45 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
const oceanic_common_layout_t *layout = device->layout; 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. // Enable progress notifications.
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
progress.maximum = progress.maximum = PAGESIZE +
(layout->rb_logbook_end - layout->rb_logbook_begin) + (layout->rb_logbook_end - layout->rb_logbook_begin) +
(layout->rb_profile_end - layout->rb_profile_begin); (layout->rb_profile_end - layout->rb_profile_begin);
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
// Read the device info. // Emit a vendor event.
rc = VTABLE(abstract)->devinfo (abstract, &progress); 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));
if (rc != DC_STATUS_SUCCESS) { if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to read the memory page.");
return rc; return rc;
} }
// Read the ringbuffer pointers. // Update and emit a progress event.
unsigned int rb_logbook_begin = 0, rb_logbook_end = 0; progress.current += PAGESIZE;
unsigned int rb_profile_begin = 0, rb_profile_end = 0; device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
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;
}
DEBUG (abstract->context, "Logbook: %08x %08x", rb_logbook_begin, rb_logbook_end); // Emit a device info event.
DEBUG (abstract->context, "Profile: %08x %08x", rb_profile_begin, rb_profile_end); 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);
// Memory buffer for the logbook data. // Memory buffer for the logbook data.
dc_buffer_t *logbook = dc_buffer_new (0); dc_buffer_t *logbook = dc_buffer_new (0);
@ -708,7 +658,7 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
} }
// Download the logbook ringbuffer. // Download the logbook ringbuffer.
rc = VTABLE(abstract)->logbook (abstract, &progress, logbook, rb_logbook_begin, rb_logbook_end); rc = VTABLE(abstract)->logbook (abstract, &progress, logbook);
if (rc != DC_STATUS_SUCCESS) { if (rc != DC_STATUS_SUCCESS) {
dc_buffer_free (logbook); dc_buffer_free (logbook);
return rc; return rc;

View File

@ -125,12 +125,8 @@ extern "C" {
#define I200CV2 0x4749 #define I200CV2 0x4749
#define GEOAIR 0x474B #define GEOAIR 0x474B
// i330r
#define DSX 0x4741
#define I330R 0x4744
#define PAGESIZE 0x10 #define PAGESIZE 0x10
#define FPMAXSIZE 0x200 #define FPMAXSIZE 0x20
#define OCEANIC_COMMON_MATCH(version,patterns,firmware) \ #define OCEANIC_COMMON_MATCH(version,patterns,firmware) \
oceanic_common_match ((version), (patterns), \ oceanic_common_match ((version), (patterns), \
@ -148,7 +144,6 @@ typedef struct oceanic_common_layout_t {
unsigned int rb_logbook_begin; unsigned int rb_logbook_begin;
unsigned int rb_logbook_end; unsigned int rb_logbook_end;
unsigned int rb_logbook_entry_size; unsigned int rb_logbook_entry_size;
unsigned int rb_logbook_direction;
// Profile ringbuffer // Profile ringbuffer
unsigned int rb_profile_begin; unsigned int rb_profile_begin;
unsigned int rb_profile_end; unsigned int rb_profile_end;
@ -173,9 +168,7 @@ typedef struct oceanic_common_device_t {
typedef struct oceanic_common_device_vtable_t { typedef struct oceanic_common_device_vtable_t {
dc_device_vtable_t base; dc_device_vtable_t base;
dc_status_t (*devinfo) (dc_device_t *device, dc_event_progress_t *progress); dc_status_t (*logbook) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook);
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); 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; } oceanic_common_device_vtable_t;
@ -193,15 +186,7 @@ void
oceanic_common_device_init (oceanic_common_device_t *device); oceanic_common_device_init (oceanic_common_device_t *device);
dc_status_t dc_status_t
oceanic_common_device_devinfo (dc_device_t *device, dc_event_progress_t *progress); oceanic_common_device_logbook (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook);
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 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); oceanic_common_device_profile (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata);

View File

@ -58,8 +58,6 @@ static const oceanic_common_device_vtable_t oceanic_veo250_device_vtable = {
NULL, /* timesync */ NULL, /* timesync */
oceanic_veo250_device_close /* close */ oceanic_veo250_device_close /* close */
}, },
oceanic_common_device_devinfo,
oceanic_common_device_pointers,
oceanic_common_device_logbook, oceanic_common_device_logbook,
oceanic_common_device_profile, oceanic_common_device_profile,
}; };
@ -72,7 +70,6 @@ static const oceanic_common_layout_t oceanic_veo250_layout = {
0x0400, /* rb_logbook_begin */ 0x0400, /* rb_logbook_begin */
0x0600, /* rb_logbook_end */ 0x0600, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0600, /* rb_profile_begin */ 0x0600, /* rb_profile_begin */
0x8000, /* rb_profile_end */ 0x8000, /* rb_profile_end */
1, /* pt_mode_global */ 1, /* pt_mode_global */

View File

@ -37,7 +37,7 @@ dc_status_t
oceanic_veo250_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); oceanic_veo250_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
oceanic_veo250_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model); oceanic_veo250_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -42,6 +42,7 @@ struct oceanic_veo250_parser_t {
double maxdepth; 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_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_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); static dc_status_t oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -49,6 +50,7 @@ static dc_status_t oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract,
static const dc_parser_vtable_t oceanic_veo250_parser_vtable = { static const dc_parser_vtable_t oceanic_veo250_parser_vtable = {
sizeof(oceanic_veo250_parser_t), sizeof(oceanic_veo250_parser_t),
DC_FAMILY_OCEANIC_VEO250, DC_FAMILY_OCEANIC_VEO250,
oceanic_veo250_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -60,7 +62,7 @@ static const dc_parser_vtable_t oceanic_veo250_parser_vtable = {
dc_status_t dc_status_t
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_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{ {
oceanic_veo250_parser_t *parser = NULL; oceanic_veo250_parser_t *parser = NULL;
@ -68,7 +70,7 @@ oceanic_veo250_parser_create (dc_parser_t **out, dc_context_t *context, const un
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (oceanic_veo250_parser_t *) dc_parser_allocate (context, &oceanic_veo250_parser_vtable, data, size); parser = (oceanic_veo250_parser_t *) dc_parser_allocate (context, &oceanic_veo250_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -86,6 +88,20 @@ oceanic_veo250_parser_create (dc_parser_t **out, dc_context_t *context, const un
} }
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 static dc_status_t
oceanic_veo250_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) oceanic_veo250_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -154,7 +170,6 @@ oceanic_veo250_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un
*((unsigned int *) value) = 1; *((unsigned int *) value) = 1;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = 0.0; gasmix->helium = 0.0;
if (data[footer + 6]) if (data[footer + 6])
gasmix->oxygen = data[footer + 6] / 100.0; gasmix->oxygen = data[footer + 6] / 100.0;
@ -215,19 +230,19 @@ oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
// Time. // Time.
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Vendor specific data // Vendor specific data
sample.vendor.type = SAMPLE_VENDOR_OCEANIC_VEO250; sample.vendor.type = SAMPLE_VENDOR_OCEANIC_VEO250;
sample.vendor.size = PAGESIZE / 2; sample.vendor.size = PAGESIZE / 2;
sample.vendor.data = data + offset; sample.vendor.data = data + offset;
if (callback) callback (DC_SAMPLE_VENDOR, &sample, userdata); if (callback) callback (DC_SAMPLE_VENDOR, sample, userdata);
// Depth (ft) // Depth (ft)
unsigned int depth = data[offset + 2]; unsigned int depth = data[offset + 2];
sample.depth = depth * FEET; sample.depth = depth * FEET;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Temperature (°F) // Temperature (°F)
unsigned int temperature; unsigned int temperature;
@ -238,7 +253,7 @@ oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
temperature = data[offset + 7]; temperature = data[offset + 7];
} }
sample.temperature = (temperature - 32.0) * (5.0 / 9.0); sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
// NDL / Deco // NDL / Deco
unsigned int have_deco = 0; unsigned int have_deco = 0;
@ -262,8 +277,7 @@ oceanic_veo250_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
sample.deco.depth = 0.0; sample.deco.depth = 0.0;
} }
sample.deco.time = decotime * 60; sample.deco.time = decotime * 60;
sample.deco.tts = 0; if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
} }
offset += PAGESIZE / 2; offset += PAGESIZE / 2;

View File

@ -51,8 +51,7 @@ typedef struct oceanic_vtpro_device_t {
oceanic_vtpro_protocol_t protocol; oceanic_vtpro_protocol_t protocol;
} oceanic_vtpro_device_t; } oceanic_vtpro_device_t;
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);
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_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); static dc_status_t oceanic_vtpro_device_close (dc_device_t *abstract);
@ -68,8 +67,6 @@ static const oceanic_common_device_vtable_t oceanic_vtpro_device_vtable = {
NULL, /* timesync */ NULL, /* timesync */
oceanic_vtpro_device_close /* close */ oceanic_vtpro_device_close /* close */
}, },
oceanic_common_device_devinfo,
oceanic_vtpro_device_pointers,
oceanic_vtpro_device_logbook, oceanic_vtpro_device_logbook,
oceanic_common_device_profile, oceanic_common_device_profile,
}; };
@ -82,7 +79,6 @@ static const oceanic_common_layout_t oceanic_vtpro_layout = {
0x0240, /* rb_logbook_begin */ 0x0240, /* rb_logbook_begin */
0x0440, /* rb_logbook_end */ 0x0440, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x0440, /* rb_profile_begin */ 0x0440, /* rb_profile_begin */
0x8000, /* rb_profile_end */ 0x8000, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -98,7 +94,6 @@ static const oceanic_common_layout_t oceanic_wisdom_layout = {
0x03D0, /* rb_logbook_begin */ 0x03D0, /* rb_logbook_begin */
0x05D0, /* rb_logbook_end */ 0x05D0, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x05D0, /* rb_profile_begin */ 0x05D0, /* rb_profile_begin */
0x8000, /* rb_profile_end */ 0x8000, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -114,7 +109,6 @@ static const oceanic_common_layout_t aeris_500ai_layout = {
0x0200, /* rb_logbook_begin */ 0x0200, /* rb_logbook_begin */
0x0200, /* rb_logbook_end */ 0x0200, /* rb_logbook_end */
8, /* rb_logbook_entry_size */ 8, /* rb_logbook_entry_size */
1, /* rb_logbook_direction */
0x00200, /* rb_profile_begin */ 0x00200, /* rb_profile_begin */
0x20000, /* rb_profile_end */ 0x20000, /* rb_profile_end */
0, /* pt_mode_global */ 0, /* pt_mode_global */
@ -292,49 +286,7 @@ oceanic_vtpro_calibrate (oceanic_vtpro_device_t *device)
} }
static dc_status_t static dc_status_t
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) oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook)
{
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; dc_status_t rc = DC_STATUS_SUCCESS;
oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract; oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract;
@ -345,25 +297,36 @@ 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 (device->base.layout->rb_logbook_begin == device->base.layout->rb_logbook_end);
assert (progress != NULL); assert (progress != NULL);
const oceanic_common_layout_t *layout = device->base.layout;
// Erase the buffer. // Erase the buffer.
if (!dc_buffer_clear (logbook)) if (!dc_buffer_clear (logbook))
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
// Get the number of dives. // Read the pointer data.
unsigned int ndives = end - begin + 1; 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];
// Update and emit a progress event. // Update and emit a progress event.
progress->maximum += ndives * PAGESIZE / 2; progress->current += PAGESIZE;
progress->maximum += PAGESIZE + (last + 1) * PAGESIZE / 2;
device_event_emit (abstract, DC_EVENT_PROGRESS, progress); device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
// Allocate memory for the logbook entries. // Allocate memory for the logbook entries.
if (!dc_buffer_reserve (logbook, ndives * PAGESIZE / 2)) if (!dc_buffer_reserve (logbook, (last + 1) * PAGESIZE / 2))
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
// Send the logbook index command. // Send the logbook index command.
unsigned char command[] = {0x52, unsigned char command[] = {0x52,
begin & 0xFF, (last >> 8) & 0xFF, // high
end & 0xFF, (last ) & 0xFF, // low
0x00}; 0x00};
rc = oceanic_vtpro_transfer (device, command, sizeof (command), NULL, 0); rc = oceanic_vtpro_transfer (device, command, sizeof (command), NULL, 0);
if (rc != DC_STATUS_SUCCESS) { if (rc != DC_STATUS_SUCCESS) {
@ -372,7 +335,7 @@ oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *p
} }
// Read the logbook index. // Read the logbook index.
for (unsigned int i = 0; i < ndives; ++i) { for (unsigned int i = 0; i < last + 1; ++i) {
// Receive the answer of the dive computer. // Receive the answer of the dive computer.
unsigned char answer[PAGESIZE / 2 + 1] = {0}; unsigned char answer[PAGESIZE / 2 + 1] = {0};
rc = dc_iostream_read (device->iostream, answer, sizeof(answer), NULL); rc = dc_iostream_read (device->iostream, answer, sizeof(answer), NULL);
@ -411,26 +374,14 @@ oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *p
} }
static dc_status_t 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) oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook)
{ {
oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract; oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract;
if (device->base.model == AERIS500AI) { if (device->base.model == AERIS500AI) {
return oceanic_aeris500ai_device_pointers (abstract, progress, rb_logbook_begin, rb_logbook_end, rb_profile_begin, rb_profile_end); return oceanic_aeris500ai_device_logbook (abstract, progress, logbook);
} else { } else {
return oceanic_common_device_pointers (abstract, progress, rb_logbook_begin, rb_logbook_end, rb_profile_begin, rb_profile_end); return oceanic_common_device_logbook (abstract, progress, logbook);
}
}
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);
} }
} }

View File

@ -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); oceanic_vtpro_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
dc_status_t dc_status_t
oceanic_vtpro_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model); oceanic_vtpro_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -42,6 +42,7 @@ struct oceanic_vtpro_parser_t {
double maxdepth; 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_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_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); static dc_status_t oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -49,6 +50,7 @@ static dc_status_t oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract,
static const dc_parser_vtable_t oceanic_vtpro_parser_vtable = { static const dc_parser_vtable_t oceanic_vtpro_parser_vtable = {
sizeof(oceanic_vtpro_parser_t), sizeof(oceanic_vtpro_parser_t),
DC_FAMILY_OCEANIC_VTPRO, DC_FAMILY_OCEANIC_VTPRO,
oceanic_vtpro_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -60,7 +62,7 @@ static const dc_parser_vtable_t oceanic_vtpro_parser_vtable = {
dc_status_t dc_status_t
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_create (dc_parser_t **out, dc_context_t *context, unsigned int model)
{ {
oceanic_vtpro_parser_t *parser = NULL; oceanic_vtpro_parser_t *parser = NULL;
@ -68,7 +70,7 @@ oceanic_vtpro_parser_create (dc_parser_t **out, dc_context_t *context, const uns
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (oceanic_vtpro_parser_t *) dc_parser_allocate (context, &oceanic_vtpro_parser_vtable, data, size); parser = (oceanic_vtpro_parser_t *) dc_parser_allocate (context, &oceanic_vtpro_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -86,6 +88,20 @@ oceanic_vtpro_parser_create (dc_parser_t **out, dc_context_t *context, const uns
} }
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 static dc_status_t
oceanic_vtpro_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) oceanic_vtpro_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -184,7 +200,6 @@ oceanic_vtpro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
*((unsigned int *) value) = 1; *((unsigned int *) value) = 1;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = 0.0; gasmix->helium = 0.0;
if (oxygen) if (oxygen)
gasmix->oxygen = oxygen / 100.0; gasmix->oxygen = oxygen / 100.0;
@ -205,7 +220,6 @@ oceanic_vtpro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
tank->gasmix = flags; tank->gasmix = flags;
tank->beginpressure = beginpressure * 2 * PSI / BAR; tank->beginpressure = beginpressure * 2 * PSI / BAR;
tank->endpressure = endpressure * 2 * PSI / BAR; tank->endpressure = endpressure * 2 * PSI / BAR;
tank->usage = DC_USAGE_NONE;
break; break;
default: default:
return DC_STATUS_UNSUPPORTED; return DC_STATUS_UNSUPPORTED;
@ -317,14 +331,14 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
time = timestamp * 60 + (i + 1) * interval; time = timestamp * 60 + (i + 1) * interval;
else else
time = timestamp * 60 + (i + 1) * 60.0 / count + 0.5; time = timestamp * 60 + (i + 1) * 60.0 / count + 0.5;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Vendor specific data // Vendor specific data
sample.vendor.type = SAMPLE_VENDOR_OCEANIC_VTPRO; sample.vendor.type = SAMPLE_VENDOR_OCEANIC_VTPRO;
sample.vendor.size = PAGESIZE / 2; sample.vendor.size = PAGESIZE / 2;
sample.vendor.data = data + offset; sample.vendor.data = data + offset;
if (callback) callback (DC_SAMPLE_VENDOR, &sample, userdata); if (callback) callback (DC_SAMPLE_VENDOR, sample, userdata);
// Depth (ft) // Depth (ft)
unsigned int depth = 0; unsigned int depth = 0;
@ -334,7 +348,7 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
depth = data[offset + 3]; depth = data[offset + 3];
} }
sample.depth = depth * FEET; sample.depth = depth * FEET;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
// Temperature (°F) // Temperature (°F)
unsigned int temperature = 0; unsigned int temperature = 0;
@ -344,7 +358,7 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
temperature = data[offset + 6]; temperature = data[offset + 6];
} }
sample.temperature = (temperature - 32.0) * (5.0 / 9.0); sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
// NDL / Deco // NDL / Deco
if (parser->model != AERIS500AI) { if (parser->model != AERIS500AI) {
@ -358,8 +372,7 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
sample.deco.depth = 0.0; sample.deco.depth = 0.0;
} }
sample.deco.time = decotime * 60; sample.deco.time = decotime * 60;
sample.deco.tts = 0; if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
} }
offset += PAGESIZE / 2; offset += PAGESIZE / 2;

View File

@ -36,7 +36,7 @@ dc_status_t
oceans_s1_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); oceans_s1_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
oceans_s1_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size); oceans_s1_parser_create (dc_parser_t **parser, dc_context_t *context);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -58,6 +58,7 @@ struct oceans_s1_parser_t {
unsigned int divetime; 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_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_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); static dc_status_t oceans_s1_parser_samples_foreach(dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata);
@ -65,6 +66,7 @@ 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 = { static const dc_parser_vtable_t oceans_s1_parser_vtable = {
sizeof(oceans_s1_parser_t), sizeof(oceans_s1_parser_t),
DC_FAMILY_OCEANS_S1, DC_FAMILY_OCEANS_S1,
oceans_s1_parser_set_data, /* set_data */
NULL, /* set_clock */ NULL, /* set_clock */
NULL, /* set_atmospheric */ NULL, /* set_atmospheric */
NULL, /* set_density */ NULL, /* set_density */
@ -75,7 +77,7 @@ static const dc_parser_vtable_t oceans_s1_parser_vtable = {
}; };
dc_status_t dc_status_t
oceans_s1_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size) oceans_s1_parser_create (dc_parser_t **out, dc_context_t *context)
{ {
oceans_s1_parser_t *parser = NULL; oceans_s1_parser_t *parser = NULL;
@ -83,7 +85,7 @@ oceans_s1_parser_create (dc_parser_t **out, dc_context_t *context, const unsigne
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (oceans_s1_parser_t *) dc_parser_allocate (context, &oceans_s1_parser_vtable, data, size); parser = (oceans_s1_parser_t *) dc_parser_allocate (context, &oceans_s1_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -103,6 +105,23 @@ oceans_s1_parser_create (dc_parser_t **out, dc_context_t *context, const unsigne
return DC_STATUS_SUCCESS; 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 static dc_status_t
oceans_s1_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) oceans_s1_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime)
{ {
@ -147,7 +166,6 @@ oceans_s1_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigne
*((unsigned int *) value) = parser->divemode == SCUBA; *((unsigned int *) value) = parser->divemode == SCUBA;
break; break;
case DC_FIELD_GASMIX: case DC_FIELD_GASMIX:
gasmix->usage = DC_USAGE_NONE;
gasmix->helium = 0.0; gasmix->helium = 0.0;
gasmix->oxygen = parser->oxygen / 100.0; gasmix->oxygen = parser->oxygen / 100.0;
gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
@ -231,19 +249,19 @@ oceans_s1_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca
unsigned int nsamples = seconds / interval; unsigned int nsamples = seconds / interval;
for (unsigned int i = 0; i < nsamples; ++i) { for (unsigned int i = 0; i < nsamples; ++i) {
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
sample.depth = 0; sample.depth = 0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
} }
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
sample.depth = depth / 100.0; sample.depth = depth / 100.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
} else if (strncmp(line, "enddive", 7) == 0) { } else if (strncmp(line, "enddive", 7) == 0) {
if (sscanf(line, "enddive %u,%u", &maxdepth, &divetime) != 2) { if (sscanf(line, "enddive %u,%u", &maxdepth, &divetime) != 2) {
ERROR (parser->base.context, "Failed to parse the line '%s'.", line); ERROR (parser->base.context, "Failed to parse the line '%s'.", line);
@ -262,14 +280,14 @@ oceans_s1_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca
} }
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
sample.depth = depth / 100.0; sample.depth = depth / 100.0;
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata); if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
sample.temperature = temperature; sample.temperature = temperature;
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
if (events & EVENT_DECO_STOP) { if (events & EVENT_DECO_STOP) {
sample.deco.type = DC_DECO_DECOSTOP; sample.deco.type = DC_DECO_DECOSTOP;
@ -280,8 +298,7 @@ oceans_s1_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca
} }
sample.deco.depth = 0.0; sample.deco.depth = 0.0;
sample.deco.time = 0; sample.deco.time = 0;
sample.deco.tts = 0; if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
if (callback) callback (DC_SAMPLE_DECO, &sample, userdata);
} }
} }

View File

@ -41,7 +41,7 @@ typedef struct dc_parser_vtable_t dc_parser_vtable_t;
struct dc_parser_t { struct dc_parser_t {
const dc_parser_vtable_t *vtable; const dc_parser_vtable_t *vtable;
dc_context_t *context; dc_context_t *context;
unsigned char *data; const unsigned char *data;
unsigned int size; unsigned int size;
}; };
@ -50,6 +50,8 @@ struct dc_parser_vtable_t {
dc_family_t type; 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_clock) (dc_parser_t *parser, unsigned int devtime, dc_ticks_t systime);
dc_status_t (*set_atmospheric) (dc_parser_t *parser, double atmospheric); dc_status_t (*set_atmospheric) (dc_parser_t *parser, double atmospheric);
@ -66,7 +68,7 @@ struct dc_parser_vtable_t {
}; };
dc_parser_t * dc_parser_t *
dc_parser_allocate (dc_context_t *context, const dc_parser_vtable_t *vtable, const unsigned char data[], size_t size); dc_parser_allocate (dc_context_t *context, const dc_parser_vtable_t *vtable);
void void
dc_parser_deallocate (dc_parser_t *parser); dc_parser_deallocate (dc_parser_t *parser);
@ -82,7 +84,7 @@ typedef struct sample_statistics_t {
#define SAMPLE_STATISTICS_INITIALIZER {0, 0.0} #define SAMPLE_STATISTICS_INITIALIZER {0, 0.0}
void void
sample_statistics_cb (dc_sample_type_t type, const dc_sample_value_t *value, void *userdata); sample_statistics_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -20,7 +20,6 @@
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <assert.h> #include <assert.h>
#include "suunto_d9.h" #include "suunto_d9.h"
@ -73,7 +72,7 @@
#define REACTPROWHITE 0x4354 #define REACTPROWHITE 0x4354
static dc_status_t static dc_status_t
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_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_status_t rc = DC_STATUS_SUCCESS; dc_status_t rc = DC_STATUS_SUCCESS;
dc_parser_t *parser = NULL; dc_parser_t *parser = NULL;
@ -83,127 +82,126 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, const unsigned
switch (family) { switch (family) {
case DC_FAMILY_SUUNTO_SOLUTION: case DC_FAMILY_SUUNTO_SOLUTION:
rc = suunto_solution_parser_create (&parser, context, data, size); rc = suunto_solution_parser_create (&parser, context);
break; break;
case DC_FAMILY_SUUNTO_EON: case DC_FAMILY_SUUNTO_EON:
rc = suunto_eon_parser_create (&parser, context, data, size, 0); rc = suunto_eon_parser_create (&parser, context, 0);
break; break;
case DC_FAMILY_SUUNTO_VYPER: case DC_FAMILY_SUUNTO_VYPER:
if (model == 0x01) if (model == 0x01)
rc = suunto_eon_parser_create (&parser, context, data, size, 1); rc = suunto_eon_parser_create (&parser, context, 1);
else else
rc = suunto_vyper_parser_create (&parser, context, data, size); rc = suunto_vyper_parser_create (&parser, context);
break; break;
case DC_FAMILY_SUUNTO_VYPER2: case DC_FAMILY_SUUNTO_VYPER2:
case DC_FAMILY_SUUNTO_D9: case DC_FAMILY_SUUNTO_D9:
rc = suunto_d9_parser_create (&parser, context, data, size, model); rc = suunto_d9_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_SUUNTO_EONSTEEL: case DC_FAMILY_SUUNTO_EONSTEEL:
rc = suunto_eonsteel_parser_create(&parser, context, data, size, model); rc = suunto_eonsteel_parser_create(&parser, context, model);
break; break;
case DC_FAMILY_UWATEC_ALADIN: case DC_FAMILY_UWATEC_ALADIN:
case DC_FAMILY_UWATEC_MEMOMOUSE: case DC_FAMILY_UWATEC_MEMOMOUSE:
rc = uwatec_memomouse_parser_create (&parser, context, data, size); rc = uwatec_memomouse_parser_create (&parser, context, devtime, systime);
break; break;
case DC_FAMILY_UWATEC_SMART: case DC_FAMILY_UWATEC_SMART:
rc = uwatec_smart_parser_create (&parser, context, data, size, model); rc = uwatec_smart_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_REEFNET_SENSUS: case DC_FAMILY_REEFNET_SENSUS:
rc = reefnet_sensus_parser_create (&parser, context, data, size); rc = reefnet_sensus_parser_create (&parser, context, devtime, systime);
break; break;
case DC_FAMILY_REEFNET_SENSUSPRO: case DC_FAMILY_REEFNET_SENSUSPRO:
rc = reefnet_sensuspro_parser_create (&parser, context, data, size); rc = reefnet_sensuspro_parser_create (&parser, context, devtime, systime);
break; break;
case DC_FAMILY_REEFNET_SENSUSULTRA: case DC_FAMILY_REEFNET_SENSUSULTRA:
rc = reefnet_sensusultra_parser_create (&parser, context, data, size); rc = reefnet_sensusultra_parser_create (&parser, context, devtime, systime);
break; break;
case DC_FAMILY_OCEANIC_VTPRO: case DC_FAMILY_OCEANIC_VTPRO:
rc = oceanic_vtpro_parser_create (&parser, context, data, size, model); rc = oceanic_vtpro_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_OCEANIC_VEO250: case DC_FAMILY_OCEANIC_VEO250:
rc = oceanic_veo250_parser_create (&parser, context, data, size, model); rc = oceanic_veo250_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_OCEANIC_ATOM2: case DC_FAMILY_OCEANIC_ATOM2:
case DC_FAMILY_PELAGIC_I330R:
if (model == REACTPROWHITE) if (model == REACTPROWHITE)
rc = oceanic_veo250_parser_create (&parser, context, data, size, model); rc = oceanic_veo250_parser_create (&parser, context, model);
else else
rc = oceanic_atom2_parser_create (&parser, context, data, size, model); rc = oceanic_atom2_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_MARES_NEMO: case DC_FAMILY_MARES_NEMO:
case DC_FAMILY_MARES_PUCK: case DC_FAMILY_MARES_PUCK:
rc = mares_nemo_parser_create (&parser, context, data, size, model); rc = mares_nemo_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_MARES_DARWIN: case DC_FAMILY_MARES_DARWIN:
rc = mares_darwin_parser_create (&parser, context, data, size, model); rc = mares_darwin_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_MARES_ICONHD: case DC_FAMILY_MARES_ICONHD:
rc = mares_iconhd_parser_create (&parser, context, data, size, model); rc = mares_iconhd_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_HW_OSTC: case DC_FAMILY_HW_OSTC:
rc = hw_ostc_parser_create (&parser, context, data, size); rc = hw_ostc_parser_create (&parser, context);
break; break;
case DC_FAMILY_HW_FROG: case DC_FAMILY_HW_FROG:
case DC_FAMILY_HW_OSTC3: case DC_FAMILY_HW_OSTC3:
rc = hw_ostc3_parser_create (&parser, context, data, size, model); rc = hw_ostc3_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_CRESSI_EDY: case DC_FAMILY_CRESSI_EDY:
case DC_FAMILY_ZEAGLE_N2ITION3: case DC_FAMILY_ZEAGLE_N2ITION3:
rc = cressi_edy_parser_create (&parser, context, data, size, model); rc = cressi_edy_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_CRESSI_LEONARDO: case DC_FAMILY_CRESSI_LEONARDO:
rc = cressi_leonardo_parser_create (&parser, context, data, size, model); rc = cressi_leonardo_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_CRESSI_GOA: case DC_FAMILY_CRESSI_GOA:
rc = cressi_goa_parser_create (&parser, context, data, size, model); rc = cressi_goa_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_ATOMICS_COBALT: case DC_FAMILY_ATOMICS_COBALT:
rc = atomics_cobalt_parser_create (&parser, context, data, size); rc = atomics_cobalt_parser_create (&parser, context);
break; break;
case DC_FAMILY_SHEARWATER_PREDATOR: case DC_FAMILY_SHEARWATER_PREDATOR:
rc = shearwater_predator_parser_create (&parser, context, data, size, model); rc = shearwater_predator_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_SHEARWATER_PETREL: case DC_FAMILY_SHEARWATER_PETREL:
rc = shearwater_petrel_parser_create (&parser, context, data, size, model); rc = shearwater_petrel_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_DIVERITE_NITEKQ: case DC_FAMILY_DIVERITE_NITEKQ:
rc = diverite_nitekq_parser_create (&parser, context, data, size); rc = diverite_nitekq_parser_create (&parser, context);
break; break;
case DC_FAMILY_CITIZEN_AQUALAND: case DC_FAMILY_CITIZEN_AQUALAND:
rc = citizen_aqualand_parser_create (&parser, context, data, size); rc = citizen_aqualand_parser_create (&parser, context);
break; break;
case DC_FAMILY_DIVESYSTEM_IDIVE: case DC_FAMILY_DIVESYSTEM_IDIVE:
rc = divesystem_idive_parser_create (&parser, context, data, size, model); rc = divesystem_idive_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_COCHRAN_COMMANDER: case DC_FAMILY_COCHRAN_COMMANDER:
rc = cochran_commander_parser_create (&parser, context, data, size, model); rc = cochran_commander_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_TECDIVING_DIVECOMPUTEREU: case DC_FAMILY_TECDIVING_DIVECOMPUTEREU:
rc = tecdiving_divecomputereu_parser_create (&parser, context, data, size); rc = tecdiving_divecomputereu_parser_create (&parser, context);
break; break;
case DC_FAMILY_MCLEAN_EXTREME: case DC_FAMILY_MCLEAN_EXTREME:
rc = mclean_extreme_parser_create (&parser, context, data, size); rc = mclean_extreme_parser_create (&parser, context);
break; break;
case DC_FAMILY_LIQUIVISION_LYNX: case DC_FAMILY_LIQUIVISION_LYNX:
rc = liquivision_lynx_parser_create (&parser, context, data, size, model); rc = liquivision_lynx_parser_create (&parser, context, model);
break; break;
case DC_FAMILY_SPORASUB_SP2: case DC_FAMILY_SPORASUB_SP2:
rc = sporasub_sp2_parser_create (&parser, context, data, size); rc = sporasub_sp2_parser_create (&parser, context);
break; break;
case DC_FAMILY_DEEPSIX_EXCURSION: case DC_FAMILY_DEEPSIX_EXCURSION:
rc = deepsix_excursion_parser_create (&parser, context, data, size); rc = deepsix_excursion_parser_create (&parser, context);
break; break;
case DC_FAMILY_SEAC_SCREEN: case DC_FAMILY_SEAC_SCREEN:
rc = seac_screen_parser_create (&parser, context, data, size); rc = seac_screen_parser_create (&parser, context);
break; break;
case DC_FAMILY_DEEPBLU_COSMIQ: case DC_FAMILY_DEEPBLU_COSMIQ:
rc = deepblu_cosmiq_parser_create (&parser, context, data, size); rc = deepblu_cosmiq_parser_create (&parser, context);
break; break;
case DC_FAMILY_OCEANS_S1: case DC_FAMILY_OCEANS_S1:
rc = oceans_s1_parser_create (&parser, context, data, size); rc = oceans_s1_parser_create (&parser, context);
break; break;
case DC_FAMILY_DIVESOFT_FREEDOM: case DC_FAMILY_DIVESOFT_FREEDOM:
rc = divesoft_freedom_parser_create (&parser, context, data, size); rc = divesoft_freedom_parser_create (&parser, context);
break; break;
default: default:
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
@ -215,42 +213,26 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, const unsigned
} }
dc_status_t dc_status_t
dc_parser_new (dc_parser_t **out, dc_device_t *device, const unsigned char data[], size_t size) dc_parser_new (dc_parser_t **out, dc_device_t *device)
{ {
dc_status_t status = DC_STATUS_SUCCESS;
dc_parser_t *parser = NULL;
if (device == NULL) if (device == NULL)
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
status = dc_parser_new_internal (&parser, device->context, data, size, return dc_parser_new_internal (out, device->context,
dc_device_get_type (device), device->devinfo.model); dc_device_get_type (device), device->devinfo.model,
if (status != DC_STATUS_SUCCESS) device->clock.devtime, device->clock.systime);
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_status_t
dc_parser_new2 (dc_parser_t **out, dc_context_t *context, dc_descriptor_t *descriptor, const unsigned char data[], size_t size) dc_parser_new2 (dc_parser_t **out, dc_context_t *context, dc_descriptor_t *descriptor, unsigned int devtime, dc_ticks_t systime)
{ {
return dc_parser_new_internal (out, context, data, size, return dc_parser_new_internal (out, context,
dc_descriptor_get_type (descriptor), dc_descriptor_get_model (descriptor)); dc_descriptor_get_type (descriptor), dc_descriptor_get_model (descriptor),
devtime, systime);
} }
dc_parser_t * dc_parser_t *
dc_parser_allocate (dc_context_t *context, const dc_parser_vtable_t *vtable, const unsigned char data[], size_t size) dc_parser_allocate (dc_context_t *context, const dc_parser_vtable_t *vtable)
{ {
dc_parser_t *parser = NULL; dc_parser_t *parser = NULL;
@ -267,34 +249,15 @@ dc_parser_allocate (dc_context_t *context, const dc_parser_vtable_t *vtable, con
// Initialize the base class. // Initialize the base class.
parser->vtable = vtable; parser->vtable = vtable;
parser->context = context; 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; return parser;
} }
void void
dc_parser_deallocate (dc_parser_t *parser) dc_parser_deallocate (dc_parser_t *parser)
{ {
if (parser == NULL)
return;
free (parser->data);
free (parser); free (parser);
} }
@ -357,6 +320,22 @@ 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_status_t
dc_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime) dc_parser_get_datetime (dc_parser_t *parser, dc_datetime_t *datetime)
{ {
@ -414,17 +393,17 @@ dc_parser_destroy (dc_parser_t *parser)
void void
sample_statistics_cb (dc_sample_type_t type, const dc_sample_value_t *value, void *userdata) sample_statistics_cb (dc_sample_type_t type, dc_sample_value_t value, void *userdata)
{ {
sample_statistics_t *statistics = (sample_statistics_t *) userdata; sample_statistics_t *statistics = (sample_statistics_t *) userdata;
switch (type) { switch (type) {
case DC_SAMPLE_TIME: case DC_SAMPLE_TIME:
statistics->divetime = value->time / 1000; statistics->divetime = value.time;
break; break;
case DC_SAMPLE_DEPTH: case DC_SAMPLE_DEPTH:
if (statistics->maxdepth < value->depth) if (statistics->maxdepth < value.depth)
statistics->maxdepth = value->depth; statistics->maxdepth = value.depth;
break; break;
default: default:
break; break;

View File

@ -1,646 +0,0 @@
/*
* 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;
}

View File

@ -28,13 +28,11 @@
struct dc_rbstream_t { struct dc_rbstream_t {
dc_device_t *device; dc_device_t *device;
dc_rbstream_direction_t direction;
unsigned int pagesize; unsigned int pagesize;
unsigned int packetsize; unsigned int packetsize;
unsigned int begin; unsigned int begin;
unsigned int end; unsigned int end;
unsigned int address; unsigned int address;
unsigned int offset;
unsigned int available; unsigned int available;
unsigned int skip; unsigned int skip;
unsigned char cache[]; unsigned char cache[];
@ -55,7 +53,7 @@ iceil (unsigned int x, unsigned int n)
} }
dc_status_t 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_direction_t direction) 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_t *rbstream = NULL; dc_rbstream_t *rbstream = NULL;
@ -80,18 +78,6 @@ dc_rbstream_new (dc_rbstream_t **out, dc_device_t *device, unsigned int pagesize
return DC_STATUS_INVALIDARGS; 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. // Address should be inside the ringbuffer.
if (address < begin || address > end) { if (address < begin || address > end) {
ERROR (device->context, "Address outside the ringbuffer!"); ERROR (device->context, "Address outside the ringbuffer!");
@ -106,64 +92,64 @@ dc_rbstream_new (dc_rbstream_t **out, dc_device_t *device, unsigned int pagesize
} }
rbstream->device = device; rbstream->device = device;
rbstream->direction = direction;
rbstream->pagesize = pagesize; rbstream->pagesize = pagesize;
rbstream->packetsize = packetsize; rbstream->packetsize = packetsize;
rbstream->begin = begin; rbstream->begin = begin;
rbstream->end = end; rbstream->end = end;
if (direction == DC_RBSTREAM_FORWARD) { rbstream->address = iceil(address, pagesize);
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->available = 0;
rbstream->skip = rbstream->address - address;
*out = rbstream; *out = rbstream;
return DC_STATUS_SUCCESS; return DC_STATUS_SUCCESS;
} }
static dc_status_t dc_status_t
dc_rbstream_read_backward (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsigned char data[], unsigned int size) dc_rbstream_read (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsigned char data[], unsigned int size)
{ {
dc_status_t rc = DC_STATUS_SUCCESS; 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 nbytes = 0;
unsigned int offset = size; unsigned int offset = size;
while (nbytes < size) { while (nbytes < size) {
if (rbstream->available == 0) { if (available == 0) {
// Handle the ringbuffer wrap point. // Handle the ringbuffer wrap point.
if (rbstream->address == rbstream->begin) if (address == rbstream->begin)
rbstream->address = rbstream->end; address = rbstream->end;
// Calculate the packet size. // Calculate the packet size.
unsigned int len = rbstream->packetsize; unsigned int len = rbstream->packetsize;
if (rbstream->begin + len > rbstream->address) if (rbstream->begin + len > address)
len = rbstream->address - rbstream->begin; len = address - rbstream->begin;
// Move to the begin of the current packet.
address -= len;
// Read the packet into the cache. // Read the packet into the cache.
rc = dc_device_read (rbstream->device, rbstream->address - len, rbstream->cache, rbstream->packetsize); rc = dc_device_read (rbstream->device, address, rbstream->cache, rbstream->packetsize);
if (rc != DC_STATUS_SUCCESS) if (rc != DC_STATUS_SUCCESS)
return rc; return rc;
// Move to the end of the next packet. available = len - skip;
rbstream->address -= len; skip = 0;
rbstream->available = len - rbstream->skip;
rbstream->skip = 0;
} }
unsigned int length = rbstream->available; unsigned int length = available;
if (nbytes + length > size) if (nbytes + length > size)
length = size - nbytes; length = size - nbytes;
offset -= length; offset -= length;
rbstream->available -= length; available -= length;
memcpy (data + offset, rbstream->cache + rbstream->available, length); memcpy (data + offset, rbstream->cache + available, length);
// Update and emit a progress event. // Update and emit a progress event.
if (progress) { if (progress) {
@ -174,76 +160,13 @@ dc_rbstream_read_backward (dc_rbstream_t *rbstream, dc_event_progress_t *progres
nbytes += length; nbytes += length;
} }
return rc; rbstream->address = address;
} rbstream->available = available;
rbstream->skip = skip;
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; 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_status_t
dc_rbstream_free (dc_rbstream_t *rbstream) dc_rbstream_free (dc_rbstream_t *rbstream)
{ {

View File

@ -33,14 +33,6 @@ extern "C" {
*/ */
typedef struct dc_rbstream_t dc_rbstream_t; 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. * Create a new ringbuffer stream.
* *
@ -51,12 +43,11 @@ typedef enum dc_rbstream_direction_t {
* @param[in] begin The ringbuffer begin address. * @param[in] begin The ringbuffer begin address.
* @param[in] end The ringbuffer end address. * @param[in] end The ringbuffer end address.
* @param[in] address The stream start 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 * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure. * on failure.
*/ */
dc_status_t 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_direction_t direction); 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);
/** /**
* Read data from the ringbuffer stream. * Read data from the ringbuffer stream.

View File

@ -36,7 +36,7 @@ dc_status_t
reefnet_sensus_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); reefnet_sensus_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream);
dc_status_t dc_status_t
reefnet_sensus_parser_create (dc_parser_t **parser, dc_context_t *context, const unsigned char data[], size_t size); reefnet_sensus_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int devtime, dc_ticks_t systime);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -48,6 +48,7 @@ struct reefnet_sensus_parser_t {
unsigned int maxdepth; 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_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_atmospheric (dc_parser_t *abstract, double atmospheric);
static dc_status_t reefnet_sensus_parser_set_density (dc_parser_t *abstract, double density); static dc_status_t reefnet_sensus_parser_set_density (dc_parser_t *abstract, double density);
@ -58,6 +59,7 @@ static dc_status_t reefnet_sensus_parser_samples_foreach (dc_parser_t *abstract,
static const dc_parser_vtable_t reefnet_sensus_parser_vtable = { static const dc_parser_vtable_t reefnet_sensus_parser_vtable = {
sizeof(reefnet_sensus_parser_t), sizeof(reefnet_sensus_parser_t),
DC_FAMILY_REEFNET_SENSUS, DC_FAMILY_REEFNET_SENSUS,
reefnet_sensus_parser_set_data, /* set_data */
reefnet_sensus_parser_set_clock, /* set_clock */ reefnet_sensus_parser_set_clock, /* set_clock */
reefnet_sensus_parser_set_atmospheric, /* set_atmospheric */ reefnet_sensus_parser_set_atmospheric, /* set_atmospheric */
reefnet_sensus_parser_set_density, /* set_density */ reefnet_sensus_parser_set_density, /* set_density */
@ -69,7 +71,7 @@ static const dc_parser_vtable_t reefnet_sensus_parser_vtable = {
dc_status_t dc_status_t
reefnet_sensus_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size) reefnet_sensus_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int devtime, dc_ticks_t systime)
{ {
reefnet_sensus_parser_t *parser = NULL; reefnet_sensus_parser_t *parser = NULL;
@ -77,7 +79,7 @@ reefnet_sensus_parser_create (dc_parser_t **out, dc_context_t *context, const un
return DC_STATUS_INVALIDARGS; return DC_STATUS_INVALIDARGS;
// Allocate memory. // Allocate memory.
parser = (reefnet_sensus_parser_t *) dc_parser_allocate (context, &reefnet_sensus_parser_vtable, data, size); parser = (reefnet_sensus_parser_t *) dc_parser_allocate (context, &reefnet_sensus_parser_vtable);
if (parser == NULL) { if (parser == NULL) {
ERROR (context, "Failed to allocate memory."); ERROR (context, "Failed to allocate memory.");
return DC_STATUS_NOMEMORY; return DC_STATUS_NOMEMORY;
@ -86,8 +88,8 @@ reefnet_sensus_parser_create (dc_parser_t **out, dc_context_t *context, const un
// Set the default values. // Set the default values.
parser->atmospheric = DEF_ATMOSPHERIC; parser->atmospheric = DEF_ATMOSPHERIC;
parser->hydrostatic = DEF_DENSITY_SALT * GRAVITY; parser->hydrostatic = DEF_DENSITY_SALT * GRAVITY;
parser->devtime = 0; parser->devtime = devtime;
parser->systime = 0; parser->systime = systime;
parser->cached = 0; parser->cached = 0;
parser->divetime = 0; parser->divetime = 0;
parser->maxdepth = 0; parser->maxdepth = 0;
@ -98,6 +100,35 @@ reefnet_sensus_parser_create (dc_parser_t **out, dc_context_t *context, const un
} }
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 static dc_status_t
reefnet_sensus_parser_set_clock (dc_parser_t *abstract, unsigned int devtime, dc_ticks_t systime) reefnet_sensus_parser_set_clock (dc_parser_t *abstract, unsigned int devtime, dc_ticks_t systime)
{ {
@ -248,13 +279,13 @@ reefnet_sensus_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
// Time (seconds) // Time (seconds)
time += interval; time += interval;
sample.time = time * 1000; sample.time = time;
if (callback) callback (DC_SAMPLE_TIME, &sample, userdata); if (callback) callback (DC_SAMPLE_TIME, sample, userdata);
// Depth (adjusted feet of seawater). // Depth (adjusted feet of seawater).
unsigned int depth = data[offset++]; unsigned int depth = data[offset++];
sample.depth = ((depth + 33.0 - (double) SAMPLE_DEPTH_ADJUST) * FSW - parser->atmospheric) / parser->hydrostatic; 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) // Temperature (degrees Fahrenheit)
if ((nsamples % 6) == 0) { if ((nsamples % 6) == 0) {
@ -262,7 +293,7 @@ reefnet_sensus_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback
return DC_STATUS_DATAFORMAT; return DC_STATUS_DATAFORMAT;
unsigned int temperature = data[offset++]; unsigned int temperature = data[offset++];
sample.temperature = (temperature - 32.0) * (5.0 / 9.0); sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
} }
// Current sample is complete. // Current sample is complete.

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