diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 86ef1162..362bfd70 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -19,7 +19,7 @@ jobs:
CC: ${{ matrix.compiler }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get install libbluetooth-dev libusb-1.0-0-dev
- run: autoreconf --install --force
@@ -30,7 +30,7 @@ jobs:
run: |
make install DESTDIR=$PWD/artifacts
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
with:
name: ${{ github.job }}-${{ matrix.compiler }}
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
@@ -50,7 +50,7 @@ jobs:
CC: ${{ matrix.compiler }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Install dependencies
run: brew install autoconf automake libtool hidapi libusb
- run: autoreconf --install --force
@@ -61,7 +61,7 @@ jobs:
run: |
make install DESTDIR=$PWD/artifacts
tar -czf ${{ github.job }}-${{ matrix.compiler }}.tar.gz -C artifacts usr
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
with:
name: ${{ github.job }}-${{ matrix.compiler }}
path: ${{ github.job }}-${{ matrix.compiler }}.tar.gz
@@ -78,7 +78,7 @@ jobs:
arch: [i686, x86_64]
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get install gcc-mingw-w64 binutils-mingw-w64 mingw-w64-tools
- name: Install libusb
@@ -118,7 +118,7 @@ jobs:
run: |
make install DESTDIR=$PWD/artifacts
tar -czf ${{ github.job }}-${{ matrix.arch }}.tar.gz -C artifacts usr
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
with:
name: ${{ github.job }}-${{ matrix.arch }}
path: ${{ github.job }}-${{ matrix.arch }}.tar.gz
@@ -161,13 +161,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- run: |
autoreconf --install --force
./configure --prefix=/usr
make -C src revision.h
- run: $ANDROID_NDK/ndk-build -C contrib/android NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk
- - uses: actions/upload-artifact@v3
+ - uses: actions/upload-artifact@v4
with:
name: ${{ github.job }}
path: contrib/android/libs
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index fcf8f23b..bc4773b5 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -9,7 +9,7 @@ jobs:
name: Release
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Version number
id: version
diff --git a/contrib/android/Android.mk b/contrib/android/Android.mk
index 43f54733..5c1c6f93 100644
--- a/contrib/android/Android.mk
+++ b/contrib/android/Android.mk
@@ -71,6 +71,7 @@ LOCAL_SRC_FILES := \
src/oceans_s1_parser.c \
src/packet.c \
src/parser.c \
+ src/pelagic_i330r.c \
src/platform.c \
src/rbstream.c \
src/reefnet_sensus.c \
diff --git a/contrib/msvc/libdivecomputer.vcxproj b/contrib/msvc/libdivecomputer.vcxproj
index 704ef8b7..991f1ac8 100644
--- a/contrib/msvc/libdivecomputer.vcxproj
+++ b/contrib/msvc/libdivecomputer.vcxproj
@@ -239,6 +239,7 @@
+
@@ -357,6 +358,7 @@
+
diff --git a/examples/common.c b/examples/common.c
index f30337ba..4f965f16 100644
--- a/examples/common.c
+++ b/examples/common.c
@@ -72,6 +72,7 @@ static const backend_table_t g_backends[] = {
{"vtpro", DC_FAMILY_OCEANIC_VTPRO, 0x4245},
{"veo250", DC_FAMILY_OCEANIC_VEO250, 0x424C},
{"atom2", DC_FAMILY_OCEANIC_ATOM2, 0x4342},
+ {"i330r", DC_FAMILY_PELAGIC_I330R, 0x4744},
{"nemo", DC_FAMILY_MARES_NEMO, 0},
{"puck", DC_FAMILY_MARES_PUCK, 7},
{"darwin", DC_FAMILY_MARES_DARWIN, 0},
diff --git a/examples/output_xml.c b/examples/output_xml.c
index 1bb673bf..0f1621d1 100644
--- a/examples/output_xml.c
+++ b/examples/output_xml.c
@@ -489,7 +489,27 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u
break;
fprintf (output->ostream, "\n",
str.desc, str.value);
+ }
+ // Parse the GPS location.
+ message ("Parsing the GPS location.\n");
+ dc_location_t location = {0};
+ status = dc_parser_get_field (parser, DC_FIELD_LOCATION, 0, &location);
+ if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
+ ERROR ("Error parsing the GPS location.");
+ goto cleanup;
+ }
+
+ if (status != DC_STATUS_UNSUPPORTED) {
+ fprintf (output->ostream,
+ "\n"
+ " %.6f\n"
+ " %.6f\n"
+ " %.2f\n"
+ "\n",
+ location.latitude,
+ location.longitude,
+ convert_depth(location.altitude, output->units));
}
// Parse the sample data.
diff --git a/include/libdivecomputer/ble.h b/include/libdivecomputer/ble.h
index 1452873a..a13fe87c 100644
--- a/include/libdivecomputer/ble.h
+++ b/include/libdivecomputer/ble.h
@@ -33,6 +33,21 @@ extern "C" {
*/
#define DC_IOCTL_BLE_GET_NAME DC_IOCTL_IOR('b', 0, DC_IOCTL_SIZE_VARIABLE)
+/**
+ * Get the bluetooth authentication PIN code.
+ *
+ * The data format is a NULL terminated string.
+ */
+#define DC_IOCTL_BLE_GET_PINCODE DC_IOCTL_IOR('b', 1, DC_IOCTL_SIZE_VARIABLE)
+
+/**
+ * Get/set the bluetooth authentication access code.
+ *
+ * The data format is a variable sized byte array.
+ */
+#define DC_IOCTL_BLE_GET_ACCESSCODE DC_IOCTL_IOR('b', 2, DC_IOCTL_SIZE_VARIABLE)
+#define DC_IOCTL_BLE_SET_ACCESSCODE DC_IOCTL_IOW('b', 2, DC_IOCTL_SIZE_VARIABLE)
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/include/libdivecomputer/common.h b/include/libdivecomputer/common.h
index 0d5ab17d..0ec8a9ff 100644
--- a/include/libdivecomputer/common.h
+++ b/include/libdivecomputer/common.h
@@ -78,6 +78,7 @@ typedef enum dc_family_t {
DC_FAMILY_OCEANIC_VTPRO = (4 << 16),
DC_FAMILY_OCEANIC_VEO250,
DC_FAMILY_OCEANIC_ATOM2,
+ DC_FAMILY_PELAGIC_I330R,
/* Mares */
DC_FAMILY_MARES_NEMO = (5 << 16),
DC_FAMILY_MARES_PUCK,
diff --git a/include/libdivecomputer/parser.h b/include/libdivecomputer/parser.h
index 0d286c84..7964f865 100644
--- a/include/libdivecomputer/parser.h
+++ b/include/libdivecomputer/parser.h
@@ -69,6 +69,7 @@ typedef enum dc_field_type_t {
DC_FIELD_DIVEMODE,
DC_FIELD_DECOMODEL,
DC_FIELD_STRING,
+ DC_FIELD_LOCATION,
} dc_field_type_t;
// Make it easy to test support compile-time with "#ifdef DC_FIELD_STRING"
@@ -279,6 +280,18 @@ typedef struct dc_field_string_t {
const char *value;
} dc_field_string_t;
+/*
+ * GPS Location
+ *
+ * The latitude and longitude are in decimal degrees, and the (optional)
+ * altitude in meters.
+ */
+typedef struct dc_location_t {
+ double latitude;
+ double longitude;
+ double altitude;
+} dc_location_t;
+
typedef union dc_sample_value_t {
unsigned int time; /* Milliseconds */
double depth;
diff --git a/src/Makefile.am b/src/Makefile.am
index 21399599..495d25e5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -43,6 +43,7 @@ libdivecomputer_la_SOURCES = \
oceanic_atom2.h oceanic_atom2.c oceanic_atom2_parser.c \
oceanic_veo250.h oceanic_veo250.c oceanic_veo250_parser.c \
oceanic_vtpro.h oceanic_vtpro.c oceanic_vtpro_parser.c \
+ pelagic_i330r.h pelagic_i330r.c \
mares_common.h mares_common.c \
mares_nemo.h mares_nemo.c mares_nemo_parser.c \
mares_puck.h mares_puck.c \
diff --git a/src/cochran_commander.c b/src/cochran_commander.c
index 38328aec..83f88009 100644
--- a/src/cochran_commander.c
+++ b/src/cochran_commander.c
@@ -603,7 +603,7 @@ cochran_commander_profile_size(cochran_commander_device_t *device, cochran_data_
// Corrupt dive, guess the end address
sample_end_address = cochran_commander_guess_sample_end_address(device, data, dive_num);
- return ringbuffer_distance(sample_start_address, sample_end_address, 0, device->layout->rb_profile_begin, device->layout->rb_profile_end);
+ return ringbuffer_distance(sample_start_address, sample_end_address, DC_RINGBUFFER_EMPTY, device->layout->rb_profile_begin, device->layout->rb_profile_end);
}
@@ -965,7 +965,7 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
last_start_address = base + array_uint32_le(data.config + layout->cf_last_log );
// Create the ringbuffer stream.
- status = dc_rbstream_new (&rbstream, abstract, 1, layout->rbstream_size, layout->rb_profile_begin, layout->rb_profile_end, last_start_address);
+ status = dc_rbstream_new (&rbstream, abstract, 1, layout->rbstream_size, layout->rb_profile_begin, layout->rb_profile_end, last_start_address, DC_RBSTREAM_BACKWARD);
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
goto error;
diff --git a/src/cressi_edy.c b/src/cressi_edy.c
index d61b84e1..c4e78c13 100644
--- a/src/cressi_edy.c
+++ b/src/cressi_edy.c
@@ -432,7 +432,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
}
// Get the number of logbook items.
- unsigned int count = ringbuffer_distance (first, last, 0, layout->rb_logbook_begin, layout->rb_logbook_end) + 1;
+ unsigned int count = ringbuffer_distance (first, last, DC_RINGBUFFER_EMPTY, layout->rb_logbook_begin, layout->rb_logbook_end) + 1;
// Get the profile pointer.
unsigned int eop = array_uint_le (logbook + layout->config + 2, layout->rb_logbook_size) * SZ_PAGE + layout->rb_profile_begin;
@@ -457,7 +457,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
}
// Get the profile length.
- unsigned int length = ringbuffer_distance (current, previous, 1, layout->rb_profile_begin, layout->rb_profile_end);
+ unsigned int length = ringbuffer_distance (current, previous, DC_RINGBUFFER_FULL, layout->rb_profile_begin, layout->rb_profile_end);
// Check for a ringbuffer overflow.
if (total + length > layout->rb_profile_end - layout->rb_profile_begin) {
@@ -481,7 +481,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
// Create the ringbuffer stream.
dc_rbstream_t *rbstream = NULL;
- rc = dc_rbstream_new (&rbstream, abstract, SZ_PAGE, SZ_PACKET, layout->rb_profile_begin, layout->rb_profile_end, eop);
+ rc = dc_rbstream_new (&rbstream, abstract, SZ_PAGE, SZ_PACKET, layout->rb_profile_begin, layout->rb_profile_end, eop, DC_RBSTREAM_BACKWARD);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
return rc;
@@ -510,7 +510,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
}
// Get the profile length.
- unsigned int length = ringbuffer_distance (current, previous, 1, layout->rb_profile_begin, layout->rb_profile_end);
+ unsigned int length = ringbuffer_distance (current, previous, DC_RINGBUFFER_FULL, layout->rb_profile_begin, layout->rb_profile_end);
// Move to the begin of the current dive.
offset -= length;
diff --git a/src/cressi_leonardo.c b/src/cressi_leonardo.c
index dd941da7..b1ec8b4d 100644
--- a/src/cressi_leonardo.c
+++ b/src/cressi_leonardo.c
@@ -41,7 +41,7 @@
#define RB_PROFILE_BEGIN 0x1438
#define RB_PROFILE_END SZ_MEMORY
-#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, 0, RB_PROFILE_BEGIN, RB_PROFILE_END)
+#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_EMPTY, RB_PROFILE_BEGIN, RB_PROFILE_END)
#define MAXRETRIES 4
#define PACKETSIZE 32
diff --git a/src/descriptor.c b/src/descriptor.c
index f47cb479..4c465b77 100644
--- a/src/descriptor.c
+++ b/src/descriptor.c
@@ -275,6 +275,9 @@ static const dc_descriptor_t g_descriptors[] = {
{"Aqualung", "i470TC", DC_FAMILY_OCEANIC_ATOM2, 0x4743, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
{"Aqualung", "i200Cv2", DC_FAMILY_OCEANIC_ATOM2, 0x4749, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
{"Oceanic", "Geo Air", DC_FAMILY_OCEANIC_ATOM2, 0x474B, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
+ /* Pelagic I330R */
+ {"Apeks", "DSX", DC_FAMILY_PELAGIC_I330R, 0x4741, DC_TRANSPORT_BLE, dc_filter_oceanic},
+ {"Aqualung", "i330R", DC_FAMILY_PELAGIC_I330R, 0x4744, DC_TRANSPORT_BLE, dc_filter_oceanic},
/* Mares Nemo */
{"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
{"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
@@ -365,6 +368,8 @@ static const dc_descriptor_t g_descriptors[] = {
{"Shearwater", "Petrel 3", DC_FAMILY_SHEARWATER_PETREL, 10, DC_TRANSPORT_BLE, dc_filter_shearwater},
{"Shearwater", "Perdix 2", DC_FAMILY_SHEARWATER_PETREL, 11, DC_TRANSPORT_BLE, dc_filter_shearwater},
{"Shearwater", "Tern", DC_FAMILY_SHEARWATER_PETREL, 12, DC_TRANSPORT_BLE, dc_filter_shearwater},
+ {"Shearwater", "Tern TX", DC_FAMILY_SHEARWATER_PETREL, 12, DC_TRANSPORT_BLE, dc_filter_shearwater},
+ {"Shearwater", "Peregrine TX", DC_FAMILY_SHEARWATER_PETREL, 13, DC_TRANSPORT_BLE, dc_filter_shearwater},
/* Dive Rite NiTek Q */
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0, DC_TRANSPORT_SERIAL, NULL},
/* Citizen Hyper Aqualand */
@@ -685,6 +690,7 @@ dc_filter_shearwater (dc_descriptor_t *descriptor, dc_transport_t transport, con
"Perdix 2",
"Teric",
"Peregrine",
+ "Peregrine TX",
"Tern"
};
@@ -762,8 +768,10 @@ dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const
0x4654, // Oceanic Veo 4.0
0x4655, // Sherwood Wisdom 4
0x4656, // Oceanic Pro Plus 4
+ 0x4741, // Apeks DSX
0x4742, // Sherwood Beacon
0x4743, // Aqualung i470TC
+ 0x4744, // Aqualung i330R
0x4749, // Aqualung i200C (newer model)
0x474B, // Oceanic Geo Air
};
diff --git a/src/device.c b/src/device.c
index f1a0ee7a..172f9411 100644
--- a/src/device.c
+++ b/src/device.c
@@ -38,6 +38,7 @@
#include "oceanic_atom2.h"
#include "oceanic_veo250.h"
#include "oceanic_vtpro.h"
+#include "pelagic_i330r.h"
#include "mares_darwin.h"
#include "mares_iconhd.h"
#include "mares_nemo.h"
@@ -165,6 +166,9 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
case DC_FAMILY_OCEANIC_ATOM2:
rc = oceanic_atom2_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
break;
+ case DC_FAMILY_PELAGIC_I330R:
+ rc = pelagic_i330r_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
+ break;
case DC_FAMILY_MARES_NEMO:
rc = mares_nemo_device_open (&device, context, iostream);
break;
diff --git a/src/divesoft_freedom_parser.c b/src/divesoft_freedom_parser.c
index efad4081..5f83656e 100644
--- a/src/divesoft_freedom_parser.c
+++ b/src/divesoft_freedom_parser.c
@@ -252,6 +252,9 @@ typedef struct divesoft_freedom_parser_t {
unsigned int seawater;
unsigned int calibration[NSENSORS];
unsigned int calibrated;
+ unsigned int have_location;
+ int latitude;
+ int longitude;
} divesoft_freedom_parser_t;
static dc_status_t divesoft_freedom_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
@@ -394,6 +397,9 @@ divesoft_freedom_cache (divesoft_freedom_parser_t *parser)
unsigned int gasmixid_previous = UNDEFINED;
+ unsigned int have_location = 0;
+ int latitude = 0;
+ int longitude = 0;
// Parse the dive profile.
unsigned int offset = headersize;
@@ -544,6 +550,14 @@ divesoft_freedom_cache (divesoft_freedom_parser_t *parser)
}
tank[idx].endpressure = pressure;
}
+ } else if (id == MEASURE_ID_GPS) {
+ if (!have_location) {
+ latitude = (signed int) array_uint32_le (data + offset + 4);
+ longitude = (signed int) array_uint32_le (data + offset + 8);
+ have_location = 1;
+ } else {
+ WARNING (abstract->context, "Multiple GPS locations present.");
+ }
}
}
@@ -636,6 +650,9 @@ divesoft_freedom_cache (divesoft_freedom_parser_t *parser)
parser->calibration[i] = calibration[i];
}
parser->calibrated = calibrated;
+ parser->have_location = have_location;
+ parser->latitude = latitude;
+ parser->longitude = longitude;
return DC_STATUS_SUCCESS;
}
@@ -690,6 +707,9 @@ divesoft_freedom_parser_create (dc_parser_t **out, dc_context_t *context, const
parser->calibration[i] = 0;
}
parser->calibrated = 0;
+ parser->have_location = 0;
+ parser->latitude = 0;
+ parser->longitude = 0;
*out = (dc_parser_t *) parser;
@@ -709,13 +729,21 @@ divesoft_freedom_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *date
return status;
unsigned int timestamp = array_uint32_le (data + 8);
- dc_ticks_t ticks = (dc_ticks_t) timestamp + EPOCH;
+
+ int timezone = 0;
+ if (parser->version == HEADER_SIGNATURE_V2) {
+ timezone = ((signed short) array_uint16_le (data + 40)) * 60;
+ } else {
+ timezone = 0;
+ }
+
+ dc_ticks_t ticks = (dc_ticks_t) timestamp + EPOCH + timezone;
if (!dc_datetime_gmtime (datetime, ticks))
return DC_STATUS_DATAFORMAT;
if (parser->version == HEADER_SIGNATURE_V2) {
- datetime->timezone = ((signed short) array_uint16_le (data + 40)) * 60;
+ datetime->timezone = timezone;
} else {
datetime->timezone = DC_TIMEZONE_NONE;
}
@@ -738,6 +766,7 @@ divesoft_freedom_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
dc_tank_t *tank = (dc_tank_t *) value;
dc_decomodel_t *decomodel = (dc_decomodel_t *) value;
+ dc_location_t *location = (dc_location_t *) value;
if (value) {
switch (type) {
@@ -833,6 +862,13 @@ divesoft_freedom_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
decomodel->params.gf.high = parser->gf_hi;
}
break;
+ case DC_FIELD_LOCATION:
+ if (!parser->have_location)
+ return DC_STATUS_UNSUPPORTED;
+ location->latitude = parser->latitude / 1000000.0;
+ location->longitude = parser->longitude / 1000000.0;
+ location->altitude = 0.0;
+ break;
default:
return DC_STATUS_UNSUPPORTED;
}
diff --git a/src/divesystem_idive_parser.c b/src/divesystem_idive_parser.c
index 3c80590d..1e7dd860 100644
--- a/src/divesystem_idive_parser.c
+++ b/src/divesystem_idive_parser.c
@@ -90,6 +90,10 @@ struct divesystem_idive_parser_t {
unsigned int algorithm;
unsigned int gf_low;
unsigned int gf_high;
+ unsigned int have_location;
+ int latitude;
+ int longitude;
+ int altitude;
};
static dc_status_t divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
@@ -149,7 +153,10 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, const
parser->algorithm = INVALID;
parser->gf_low = INVALID;
parser->gf_high = INVALID;
-
+ parser->have_location = 0;
+ parser->latitude = 0;
+ parser->longitude = 0;
+ parser->altitude = 0;
*out = (dc_parser_t*) parser;
@@ -276,6 +283,7 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
dc_tank_t *tank = (dc_tank_t *) value;
dc_salinity_t *water = (dc_salinity_t *) value;
dc_decomodel_t *decomodel = (dc_decomodel_t *) value;
+ dc_location_t *location = (dc_location_t *) value;
if (value) {
switch (type) {
@@ -381,6 +389,13 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
}
}
break;
+ case DC_FIELD_LOCATION:
+ if (!parser->have_location)
+ return DC_STATUS_UNSUPPORTED;
+ location->latitude = parser->latitude / 10000000.0;
+ location->longitude = parser->longitude / 10000000.0;
+ location->altitude = parser->altitude / 1000.0;
+ break;
default:
return DC_STATUS_UNSUPPORTED;
}
@@ -438,6 +453,9 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
firmware = array_uint32_le(data + 0x2E);
}
+ unsigned int have_location = 0;
+ int altitude = 0, longitude = 0, latitude = 0;
+
unsigned int offset = parser->headersize;
while (offset + samplesize <= size) {
dc_sample_value_t sample = {0};
@@ -447,6 +465,17 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
array_uint16_le (data + offset + 52) :
REC_SAMPLE;
if (type != REC_SAMPLE) {
+ if (type == REC_INFO) {
+ if (!have_location) {
+ altitude = (signed int) array_uint32_le (data + offset + 40);
+ longitude = (signed int) array_uint32_le (data + offset + 44);
+ latitude = (signed int) array_uint32_le (data + offset + 48);
+ have_location = 1;
+ } else {
+ WARNING (abstract->context, "Multiple GPS locations present.");
+ }
+ }
+
// Skip non-sample records.
offset += samplesize;
continue;
@@ -649,6 +678,10 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
parser->algorithm = algorithm;
parser->gf_low = gf_low;
parser->gf_high = gf_high;
+ parser->have_location = have_location;
+ parser->latitude = latitude;
+ parser->longitude = longitude;
+ parser->altitude = altitude;
parser->cached = 1;
return DC_STATUS_SUCCESS;
diff --git a/src/hw_frog.c b/src/hw_frog.c
index f98523b5..2de4ebac 100644
--- a/src/hw_frog.c
+++ b/src/hw_frog.c
@@ -40,7 +40,7 @@
#define RB_PROFILE_BEGIN 0x000000
#define RB_PROFILE_END 0x200000
-#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, 0, RB_PROFILE_BEGIN, RB_PROFILE_END)
+#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_EMPTY, RB_PROFILE_BEGIN, RB_PROFILE_END)
#define READY 0x4D
#define HEADER 0x61
diff --git a/src/liquivision_lynx.c b/src/liquivision_lynx.c
index b755955e..3ce87438 100644
--- a/src/liquivision_lynx.c
+++ b/src/liquivision_lynx.c
@@ -67,12 +67,12 @@
#define RB_LOGBOOK_BEGIN (1 * PAGESIZE)
#define RB_LOGBOOK_END (25 * PAGESIZE)
#define RB_LOGBOOK_SIZE (RB_LOGBOOK_END - RB_LOGBOOK_BEGIN)
-#define RB_LOGBOOK_DISTANCE(a,b) ringbuffer_distance (a, b, 1, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END)
+#define RB_LOGBOOK_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_FULL, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END)
#define RB_PROFILE_BEGIN (25 * PAGESIZE)
#define RB_PROFILE_END (500 * PAGESIZE)
#define RB_PROFILE_SIZE (RB_PROFILE_END - RB_PROFILE_BEGIN)
-#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, 1, RB_PROFILE_BEGIN, RB_PROFILE_END)
+#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_FULL, RB_PROFILE_BEGIN, RB_PROFILE_END)
#define SZ_HEADER_XEN 80
#define SZ_HEADER_OTHER 96
@@ -469,7 +469,7 @@ liquivision_lynx_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
// Create the ringbuffer stream.
dc_rbstream_t *rblogbook = NULL;
- status = dc_rbstream_new (&rblogbook, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END, rb_logbook_end);
+ status = dc_rbstream_new (&rblogbook, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END, rb_logbook_end, DC_RBSTREAM_BACKWARD);
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
goto error_free_logbook;
@@ -600,7 +600,7 @@ liquivision_lynx_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
// Create the ringbuffer stream.
dc_rbstream_t *rbprofile = NULL;
- status = dc_rbstream_new (&rbprofile, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_PROFILE_BEGIN, RB_PROFILE_END, rb_profile_end);
+ status = dc_rbstream_new (&rbprofile, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_PROFILE_BEGIN, RB_PROFILE_END, rb_profile_end, DC_RBSTREAM_BACKWARD);
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
goto error_free_profile;
diff --git a/src/mares_iconhd.c b/src/mares_iconhd.c
index 03b00e51..92073ac3 100644
--- a/src/mares_iconhd.c
+++ b/src/mares_iconhd.c
@@ -80,7 +80,7 @@
#define VARIABLE 1
#define ACK 0xAA
-#define EOF 0xEA
+#define END 0xEA
#define XOR 0xA5
#define CMD_VERSION 0xC2
@@ -230,7 +230,7 @@ mares_iconhd_packet_fixed (mares_iconhd_device_t *device,
};
status = dc_iostream_write (device->iostream, command, sizeof(command), NULL);
if (status != DC_STATUS_SUCCESS) {
- ERROR (abstract->context, "Failed to send the command.");
+ ERROR (abstract->context, "Failed to send the command header.");
return status;
}
@@ -238,7 +238,7 @@ mares_iconhd_packet_fixed (mares_iconhd_device_t *device,
if (size && transport == DC_TRANSPORT_BLE) {
status = dc_iostream_write (device->iostream, data, size, NULL);
if (status != DC_STATUS_SUCCESS) {
- ERROR (abstract->context, "Failed to send the command.");
+ ERROR (abstract->context, "Failed to send the command data.");
return status;
}
}
@@ -247,13 +247,13 @@ mares_iconhd_packet_fixed (mares_iconhd_device_t *device,
unsigned char header[1] = {0};
status = dc_iostream_read (device->iostream, header, sizeof (header), NULL);
if (status != DC_STATUS_SUCCESS) {
- ERROR (abstract->context, "Failed to receive the answer.");
+ ERROR (abstract->context, "Failed to receive the packet header.");
return status;
}
// Verify the header byte.
if (header[0] != ACK) {
- ERROR (abstract->context, "Unexpected answer byte.");
+ ERROR (abstract->context, "Unexpected packet header byte (%02x).", header[0]);
return DC_STATUS_PROTOCOL;
}
@@ -269,7 +269,7 @@ mares_iconhd_packet_fixed (mares_iconhd_device_t *device,
// Read the packet.
status = dc_iostream_read (device->iostream, answer, asize, NULL);
if (status != DC_STATUS_SUCCESS) {
- ERROR (abstract->context, "Failed to receive the answer.");
+ ERROR (abstract->context, "Failed to receive the packet data.");
return status;
}
@@ -277,13 +277,13 @@ mares_iconhd_packet_fixed (mares_iconhd_device_t *device,
unsigned char trailer[1] = {0};
status = dc_iostream_read (device->iostream, trailer, sizeof (trailer), NULL);
if (status != DC_STATUS_SUCCESS) {
- ERROR (abstract->context, "Failed to receive the answer.");
+ ERROR (abstract->context, "Failed to receive the packet trailer.");
return status;
}
// Verify the trailer byte.
- if (trailer[0] != EOF) {
- ERROR (abstract->context, "Unexpected answer byte.");
+ if (trailer[0] != END) {
+ ERROR (abstract->context, "Unexpected packet trailer byte (%02x).", trailer[0]);
return DC_STATUS_PROTOCOL;
}
@@ -358,7 +358,7 @@ mares_iconhd_packet_variable (mares_iconhd_device_t *device,
}
// Verify the trailer byte.
- if (packet[length - 1] != EOF) {
+ if (packet[length - 1] != END) {
ERROR (abstract->context, "Unexpected packet trailer byte (%02x).", packet[length - 1]);
return DC_STATUS_PROTOCOL;
}
@@ -876,7 +876,7 @@ mares_iconhd_device_foreach_raw (dc_device_t *abstract, dc_dive_callback_t callb
// Create the ringbuffer stream.
dc_rbstream_t *rbstream = NULL;
- rc = dc_rbstream_new (&rbstream, abstract, 1, device->packetsize, layout->rb_profile_begin, layout->rb_profile_end, eop);
+ rc = dc_rbstream_new (&rbstream, abstract, 1, device->packetsize, layout->rb_profile_begin, layout->rb_profile_end, eop, DC_RBSTREAM_BACKWARD);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
return rc;
diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c
index d9f3a6d6..6c7da77c 100644
--- a/src/oceanic_atom2.c
+++ b/src/oceanic_atom2.c
@@ -86,6 +86,8 @@ static const oceanic_common_device_vtable_t oceanic_atom2_device_vtable = {
NULL, /* timesync */
oceanic_atom2_device_close /* close */
},
+ oceanic_common_device_devinfo,
+ oceanic_common_device_pointers,
oceanic_common_device_logbook,
oceanic_common_device_profile,
};
@@ -98,10 +100,11 @@ static const oceanic_common_layout_t aeris_f10_layout = {
0x0100, /* rb_logbook_begin */
0x0D80, /* rb_logbook_end */
32, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0D80, /* rb_profile_begin */
0x10000, /* rb_profile_end */
0, /* pt_mode_global */
- 2, /* pt_mode_logbook */
+ 3, /* pt_mode_logbook */
0, /* pt_mode_serial */
};
@@ -113,10 +116,11 @@ static const oceanic_common_layout_t aeris_f11_layout = {
0x0100, /* rb_logbook_begin */
0x0D80, /* rb_logbook_end */
32, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0D80, /* rb_profile_begin */
0x20000, /* rb_profile_end */
0, /* pt_mode_global */
- 3, /* pt_mode_logbook */
+ 2, /* pt_mode_logbook */
0, /* pt_mode_serial */
};
@@ -128,6 +132,7 @@ static const oceanic_common_layout_t oceanic_default_layout = {
0x0240, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */
0x10000, /* rb_profile_end */
0, /* pt_mode_global */
@@ -143,6 +148,7 @@ static const oceanic_common_layout_t oceanic_atom1_layout = {
0x0240, /* rb_logbook_begin */
0x0440, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0440, /* rb_profile_begin */
0x8000, /* rb_profile_end */
0, /* pt_mode_global */
@@ -158,6 +164,7 @@ static const oceanic_common_layout_t oceanic_atom2a_layout = {
0x0240, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */
0xFE00, /* rb_profile_end */
0, /* pt_mode_global */
@@ -173,6 +180,7 @@ static const oceanic_common_layout_t oceanic_atom2b_layout = {
0x0240, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */
0xFE00, /* rb_profile_end */
0, /* pt_mode_global */
@@ -188,6 +196,7 @@ static const oceanic_common_layout_t oceanic_atom2c_layout = {
0x0240, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */
0xFFF0, /* rb_profile_end */
0, /* pt_mode_global */
@@ -203,6 +212,7 @@ static const oceanic_common_layout_t sherwood_wisdom_layout = {
0x03D0, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */
0xFE00, /* rb_profile_end */
0, /* pt_mode_global */
@@ -218,6 +228,7 @@ static const oceanic_common_layout_t oceanic_proplus3_layout = {
0x03E0, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */
0xFE00, /* rb_profile_end */
0, /* pt_mode_global */
@@ -233,6 +244,7 @@ static const oceanic_common_layout_t tusa_zenair_layout = {
0x0240, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */
0xFE00, /* rb_profile_end */
0, /* pt_mode_global */
@@ -248,6 +260,7 @@ static const oceanic_common_layout_t oceanic_oc1_layout = {
0x0240, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */
0x1FE00, /* rb_profile_end */
0, /* pt_mode_global */
@@ -263,6 +276,7 @@ static const oceanic_common_layout_t oceanic_oci_layout = {
0x10C0, /* rb_logbook_begin */
0x1400, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x1400, /* rb_profile_begin */
0x1FE00, /* rb_profile_end */
0, /* pt_mode_global */
@@ -278,6 +292,7 @@ static const oceanic_common_layout_t oceanic_atom3_layout = {
0x0400, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */
0x1FE00, /* rb_profile_end */
0, /* pt_mode_global */
@@ -293,6 +308,7 @@ static const oceanic_common_layout_t oceanic_vt4_layout = {
0x0420, /* rb_logbook_begin */
0x0A40, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0A40, /* rb_profile_begin */
0x1FE00, /* rb_profile_end */
0, /* pt_mode_global */
@@ -308,6 +324,7 @@ static const oceanic_common_layout_t hollis_tx1_layout = {
0x0780, /* rb_logbook_begin */
0x1000, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x1000, /* rb_profile_begin */
0x40000, /* rb_profile_end */
0, /* pt_mode_global */
@@ -323,6 +340,7 @@ static const oceanic_common_layout_t oceanic_veo1_layout = {
0x0400, /* rb_logbook_begin */
0x0400, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0400, /* rb_profile_begin */
0x0400, /* rb_profile_end */
0, /* pt_mode_global */
@@ -338,6 +356,7 @@ static const oceanic_common_layout_t oceanic_reactpro_layout = {
0x0400, /* rb_logbook_begin */
0x0600, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0600, /* rb_profile_begin */
0xFE00, /* rb_profile_end */
1, /* pt_mode_global */
@@ -353,6 +372,7 @@ static const oceanic_common_layout_t oceanic_proplusx_layout = {
0x1000, /* rb_logbook_begin */
0x10000, /* rb_logbook_end */
16, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x40000, /* rb_profile_begin */
0x440000, /* rb_profile_end */
0, /* pt_mode_global */
@@ -368,6 +388,7 @@ static const oceanic_common_layout_t aqualung_i770r_layout = {
0x2000, /* rb_logbook_begin */
0x10000, /* rb_logbook_end */
16, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x40000, /* rb_profile_begin */
0x640000, /* rb_profile_end */
0, /* pt_mode_global */
@@ -383,6 +404,7 @@ static const oceanic_common_layout_t aeris_a300cs_layout = {
0x0900, /* rb_logbook_begin */
0x1000, /* rb_logbook_end */
16, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x1000, /* rb_profile_begin */
0x3FE00, /* rb_profile_end */
0, /* pt_mode_global */
@@ -398,6 +420,7 @@ static const oceanic_common_layout_t aqualung_i450t_layout = {
0x10C0, /* rb_logbook_begin */
0x1400, /* rb_logbook_end */
16, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x1400, /* rb_profile_begin */
0x3FE00, /* rb_profile_end */
0, /* pt_mode_global */
@@ -415,13 +438,14 @@ static const oceanic_common_version_t versions[] = {
{"MANTA R\0\0 512K", 0, MANTA, &oceanic_atom2c_layout},
{"2M ATOM r\0\0 512K", 0x3349, ATOM2, &oceanic_atom2a_layout},
{"2M ATOM r\0\0 512K", 0, ATOM2, &oceanic_atom2c_layout},
+ {"OCE GEO R\0\0 512K", 0x3242, GEO, &oceanic_atom2a_layout},
+ {"OCE GEO R\0\0 512K", 0, GEO, &oceanic_atom2c_layout},
{"INSIGHT2 \0\0 512K", 0, INSIGHT2, &oceanic_atom2a_layout},
{"OCEVEO30 \0\0 512K", 0, VEO30, &oceanic_atom2a_layout},
{"ATMOSAI R\0\0 512K", 0, ATMOSAI2, &oceanic_atom2a_layout},
{"PROPLUS2 \0\0 512K", 0, PROPLUS21, &oceanic_atom2a_layout},
{"OCEGEO20 \0\0 512K", 0, GEO20, &oceanic_atom2a_layout},
- {"OCE GEO R\0\0 512K", 0, GEO, &oceanic_atom2a_layout},
{"AQUAI200 \0\0 512K", 0, I200, &oceanic_atom2a_layout},
{"AQUA200C \0\0 512K", 0, I200C, &oceanic_atom2a_layout},
diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c
index fe50796d..a8304471 100644
--- a/src/oceanic_atom2_parser.c
+++ b/src/oceanic_atom2_parser.c
@@ -37,6 +37,12 @@
#define GAUGE 1
#define FREEDIVE 2
+#define DSX_CC 0
+#define DSX_OC 1
+#define DSX_SIDEMOUNT 2
+#define DSX_SIDEGAUGE 3
+#define DSX_GAUGE 4
+
#define NGASMIXES 6
#define HEADER 1
@@ -47,6 +53,7 @@ typedef struct oceanic_atom2_parser_t oceanic_atom2_parser_t;
struct oceanic_atom2_parser_t {
dc_parser_t base;
unsigned int model;
+ unsigned int logbooksize;
unsigned int headersize;
unsigned int footersize;
unsigned int serial;
@@ -78,6 +85,11 @@ static const dc_parser_vtable_t oceanic_atom2_parser_vtable = {
NULL /* destroy */
};
+static unsigned int
+is_freedive (unsigned int divemode, unsigned int model)
+{
+ return divemode == FREEDIVE && model != DSX;
+}
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, unsigned int serial)
@@ -96,6 +108,7 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, const uns
// Set the default values.
parser->model = model;
+ parser->logbooksize = 0;
parser->headersize = 9 * PAGESIZE / 2;
parser->footersize = 2 * PAGESIZE / 2;
if (model == DATAMASK || model == COMPUMASK ||
@@ -134,6 +147,14 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, const uns
} else if (model == I550C || model == WISDOM4 ||
model == I200CV2) {
parser->headersize = 5 * PAGESIZE / 2;
+ } else if (model == I330R) {
+ parser->logbooksize = 64;
+ parser->headersize = parser->logbooksize + 80;
+ parser->footersize = 48;
+ } else if (model == DSX) {
+ parser->logbooksize = 512;
+ parser->headersize = parser->logbooksize + 256;
+ parser->footersize = 64;
}
parser->serial = serial;
@@ -174,8 +195,18 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim
if (datetime) {
// AM/PM bit of the 12-hour clock.
unsigned int pm = p[1] & 0x80;
+ unsigned int have_ampm = 1;
switch (parser->model) {
+ case I330R:
+ case DSX:
+ datetime->year = p[7] + 2000;
+ datetime->month = p[6];
+ datetime->day = p[5];
+ datetime->hour = p[3];
+ datetime->minute = p[4];
+ have_ampm = 0;
+ break;
case OC1A:
case OC1B:
case OC1C:
@@ -284,9 +315,11 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim
datetime->timezone = DC_TIMEZONE_NONE;
// Convert to a 24-hour clock.
- datetime->hour %= 12;
- if (pm)
- datetime->hour += 12;
+ if (have_ampm) {
+ datetime->hour %= 12;
+ if (pm)
+ datetime->hour += 12;
+ }
/*
* Workaround for the year 2010 problem.
@@ -362,6 +395,10 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
} else if (parser->model == VEO20 || parser->model == VEO30 ||
parser->model == OCS) {
mode = (data[1] & 0x60) >> 5;
+ } else if (parser->model == I330R) {
+ mode = data[2];
+ } else if (parser->model == DSX) {
+ mode = data[45];
}
// Get the gas mixes.
@@ -369,7 +406,7 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
unsigned int o2_offset = 0;
unsigned int he_offset = 0;
unsigned int o2_step = 1;
- if (mode == FREEDIVE) {
+ if (is_freedive (mode, parser->model)) {
ngasmixes = 0;
} else if (parser->model == DATAMASK || parser->model == COMPUMASK) {
ngasmixes = 1;
@@ -419,6 +456,17 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
} else if (parser->model == WISDOM4) {
o2_offset = header + 4;
ngasmixes = 1;
+ } else if (parser->model == I330R) {
+ ngasmixes = 3;
+ o2_offset = parser->logbooksize + 16;
+ } else if (parser->model == DSX) {
+ if (mode < DSX_SIDEGAUGE) {
+ o2_offset = parser->logbooksize + 0x89 + mode * 16;
+ he_offset = parser->logbooksize + 0xB9 + mode * 16;
+ ngasmixes = 6;
+ } else {
+ ngasmixes = 0;
+ }
} else {
o2_offset = header + 4;
ngasmixes = 3;
@@ -432,6 +480,10 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
for (unsigned int i = 0; i < ngasmixes; ++i) {
if (data[o2_offset + i * o2_step]) {
parser->oxygen[i] = data[o2_offset + i * o2_step];
+ // The i330R uses 20 as "Air" and 21 as 21% Nitrox
+ if (parser->model == I330R && parser->oxygen[i] == 20) {
+ parser->oxygen[i] = 21;
+ }
} else {
parser->oxygen[i] = 21;
}
@@ -493,9 +545,18 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
parser->model == F11A || parser->model == F11B ||
parser->model == MUNDIAL2 || parser->model == MUNDIAL3)
*((double *) value) = array_uint16_le (data + 4) / 16.0 * FEET;
+ else if (parser->model == I330R || parser->model == DSX)
+ *((double *) value) = array_uint16_le (data + parser->footer + 10) / 10.0 * FEET;
else
*((double *) value) = (array_uint16_le (data + parser->footer + 4) & 0x0FFF) / 16.0 * FEET;
break;
+ case DC_FIELD_AVGDEPTH:
+ if (parser->model == I330R || parser->model == DSX) {
+ *((double *) value) = array_uint16_le (data + parser->footer + 12) / 10.0 * FEET;
+ } else {
+ return DC_STATUS_UNSUPPORTED;
+ }
+ break;
case DC_FIELD_GASMIX_COUNT:
*((unsigned int *) value) = parser->ngasmixes;
break;
@@ -514,23 +575,49 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
water->type = DC_WATER_SALT;
}
water->density = 0.0;
+ } else if (parser->model == I330R || parser->model == DSX) {
+ unsigned int settings = array_uint32_le (data + parser->logbooksize + 12);
+ if (settings & 0x10000) {
+ water->type = DC_WATER_FRESH;
+ } else {
+ water->type = DC_WATER_SALT;
+ }
+ water->density = 0.0;
} else {
return DC_STATUS_UNSUPPORTED;
}
break;
case DC_FIELD_DIVEMODE:
- switch (parser->mode) {
- case NORMAL:
- *((unsigned int *) value) = DC_DIVEMODE_OC;
- break;
- case GAUGE:
- *((unsigned int *) value) = DC_DIVEMODE_GAUGE;
- break;
- case FREEDIVE:
- *((unsigned int *) value) = DC_DIVEMODE_FREEDIVE;
- break;
- default:
- return DC_STATUS_DATAFORMAT;
+ if (parser->model == DSX) {
+ switch (parser->mode) {
+ case DSX_OC:
+ case DSX_SIDEMOUNT:
+ *((unsigned int *) value) = DC_DIVEMODE_OC;
+ break;
+ case DSX_SIDEGAUGE:
+ case DSX_GAUGE:
+ *((unsigned int *) value) = DC_DIVEMODE_GAUGE;
+ break;
+ case DSX_CC:
+ *((unsigned int *) value) = DC_DIVEMODE_CCR;
+ break;
+ default:
+ return DC_STATUS_DATAFORMAT;
+ }
+ } else {
+ switch (parser->mode) {
+ case NORMAL:
+ *((unsigned int *) value) = DC_DIVEMODE_OC;
+ break;
+ case GAUGE:
+ *((unsigned int *) value) = DC_DIVEMODE_GAUGE;
+ break;
+ case FREEDIVE:
+ *((unsigned int *) value) = DC_DIVEMODE_FREEDIVE;
+ break;
+ default:
+ return DC_STATUS_DATAFORMAT;
+ }
}
break;
case DC_FIELD_STRING:
@@ -560,7 +647,7 @@ oceanic_atom2_parser_vendor (oceanic_atom2_parser_t *parser, const unsigned char
dc_sample_value_t sample = {0};
// Ignore empty samples.
- if ((parser->mode != FREEDIVE &&
+ if ((!is_freedive (parser->mode, parser->model) &&
array_isequal (data + offset, samplesize, 0x00)) ||
array_isequal (data + offset, samplesize, 0xFF)) {
offset += samplesize;
@@ -569,7 +656,7 @@ oceanic_atom2_parser_vendor (oceanic_atom2_parser_t *parser, const unsigned char
// Get the sample type.
unsigned int sampletype = data[offset + 0];
- if (parser->mode == FREEDIVE)
+ if (is_freedive (parser->mode, parser->model))
sampletype = 0;
// Get the sample size.
@@ -605,16 +692,20 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
unsigned int extratime = 0;
unsigned int time = 0;
unsigned int interval = 1000;
- if (parser->mode != FREEDIVE) {
- unsigned int offset = 0x17;
- if (parser->model == A300CS || parser->model == VTX ||
- parser->model == I450T || parser->model == I750TC ||
- parser->model == PROPLUSX || parser->model == I770R ||
- parser->model == SAGE || parser->model == BEACON)
- offset = 0x1f;
- const unsigned int intervals[] = {2000, 15000, 30000, 60000};
- unsigned int idx = data[offset] & 0x03;
- interval = intervals[idx];
+ if (!is_freedive (parser->mode, parser->model)) {
+ if (parser->model == I330R || parser->model == DSX) {
+ interval = data[parser->logbooksize + 36] * 1000;
+ } else {
+ unsigned int offset = 0x17;
+ if (parser->model == A300CS || parser->model == VTX ||
+ parser->model == I450T || parser->model == I750TC ||
+ parser->model == PROPLUSX || parser->model == I770R ||
+ parser->model == SAGE || parser->model == BEACON)
+ offset = 0x1f;
+ const unsigned int intervals[] = {2000, 15000, 30000, 60000};
+ unsigned int idx = data[offset] & 0x03;
+ interval = intervals[idx];
+ }
} else if (parser->model == F11A || parser->model == F11B) {
const unsigned int intervals[] = {250, 500, 1000, 2000};
unsigned int idx = data[0x29] & 0x03;
@@ -622,7 +713,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
}
unsigned int samplesize = PAGESIZE / 2;
- if (parser->mode == FREEDIVE) {
+ if (is_freedive (parser->mode, parser->model)) {
if (parser->model == F10A || parser->model == F10B ||
parser->model == F11A || parser->model == F11B ||
parser->model == MUNDIAL2 || parser->model == MUNDIAL3) {
@@ -637,12 +728,14 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
parser->model == I750TC || parser->model == PROPLUSX ||
parser->model == I770R || parser->model == I470TC ||
parser->model == SAGE || parser->model == BEACON ||
- parser->model == GEOAIR) {
+ parser->model == GEOAIR || parser->model == I330R) {
samplesize = PAGESIZE;
+ } else if (parser->model == DSX) {
+ samplesize = 32;
}
unsigned int have_temperature = 1, have_pressure = 1;
- if (parser->mode == FREEDIVE) {
+ if (is_freedive (parser->mode, parser->model)) {
have_temperature = 0;
have_pressure = 0;
} else if (parser->model == VEO30 || parser->model == OCS ||
@@ -653,7 +746,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
parser->model == I200 || parser->model == I100 ||
parser->model == I300C || parser->model == TALIS ||
parser->model == I200C || parser->model == I200CV2 ||
- parser->model == GEO40 || parser->model == VEO40) {
+ parser->model == GEO40 || parser->model == VEO40 ||
+ parser->model == I330R) {
have_pressure = 0;
}
@@ -664,7 +758,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
}
// Initial tank pressure.
- unsigned int tank = 0;
+ unsigned int tank = 1;
unsigned int pressure = 0;
if (have_pressure) {
unsigned int idx = 2;
@@ -687,7 +781,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
dc_sample_value_t sample = {0};
// Ignore empty samples.
- if ((parser->mode != FREEDIVE &&
+ if ((!is_freedive (parser->mode, parser->model) &&
array_isequal (data + offset, samplesize, 0x00)) ||
array_isequal (data + offset, samplesize, 0xFF)) {
offset += samplesize;
@@ -701,7 +795,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
// Get the sample type.
unsigned int sampletype = data[offset + 0];
- if (parser->mode == FREEDIVE)
+ if (is_freedive (parser->mode, parser->model))
sampletype = 0;
// The sample size is usually fixed, but some sample types have a
@@ -719,17 +813,17 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
if (sampletype == 0xAA) {
if (parser->model == DATAMASK || parser->model == COMPUMASK) {
// Tank pressure (1 psi) and number
- tank = 0;
+ tank = 1;
pressure = (((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF);
} else if (parser->model == A300CS || parser->model == VTX ||
parser->model == I750TC || parser->model == I770R ||
parser->model == SAGE || parser->model == BEACON) {
// Tank pressure (1 psi) and number (one based index)
- tank = (data[offset + 1] & 0x03) - 1;
+ tank = data[offset + 1] & 0x03;
pressure = ((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF;
} else {
// Tank pressure (2 psi) and number (one based index)
- tank = (data[offset + 1] & 0x03) - 1;
+ tank = data[offset + 1] & 0x03;
if (parser->model == ATOM2 || parser->model == EPICA || parser->model == EPICB)
pressure = (((data[offset + 3] << 8) + data[offset + 4]) & 0x0FFF) * 2;
else
@@ -822,6 +916,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
parser->model == I770R|| parser->model == SAGE ||
parser->model == BEACON) {
temperature = data[offset + 11];
+ } else if (parser->model == I330R || parser->model == DSX) {
+ temperature = array_uint16_le(data + offset + 10);
} else {
unsigned int sign;
if (parser->model == DG03 || parser->model == PROPLUS3 ||
@@ -844,7 +940,11 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
else
temperature += (data[offset + 7] & 0x0C) >> 2;
}
- sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
+ if (parser->model == I330R || parser->model == DSX) {
+ sample.temperature = ((temperature / 10.0) - 32.0) * (5.0 / 9.0);
+ } else {
+ sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
+ }
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
}
@@ -869,16 +969,22 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
parser->model == PROPLUSX || parser->model == I770R ||
parser->model == SAGE || parser->model == BEACON)
pressure = array_uint16_le (data + offset + 4);
- else
+ else if (parser->model == DSX) {
+ pressure = array_uint16_le (data + offset + 14);
+ tank = (data[offset] & 0xF0) >> 4;
+ } else {
pressure -= data[offset + 1];
- sample.pressure.tank = tank;
- sample.pressure.value = pressure * PSI / BAR;
- if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
+ }
+ if (tank) {
+ sample.pressure.tank = tank - 1;
+ sample.pressure.value = pressure * PSI / BAR;
+ if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
+ }
}
// Depth (1/16 ft)
unsigned int depth;
- if (parser->mode == FREEDIVE)
+ if (is_freedive (parser->mode, parser->model))
depth = array_uint16_le (data + offset);
else if (parser->model == GEO20 || parser->model == VEO20 ||
parser->model == VEO30 || parser->model == OC1A ||
@@ -891,11 +997,17 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
parser->model == I470TC || parser->model == I200CV2 ||
parser->model == GEOAIR)
depth = (data[offset + 4] + (data[offset + 5] << 8)) & 0x0FFF;
+ else if (parser->model == I330R || parser->model == DSX)
+ depth = array_uint16_le (data + offset + 2);
else if (parser->model == ATOM1)
depth = data[offset + 3] * 16;
else
depth = (data[offset + 2] + (data[offset + 3] << 8)) & 0x0FFF;
- sample.depth = depth / 16.0 * FEET;
+ if (parser->model == I330R || parser->model == DSX) {
+ sample.depth = depth / 10.0 * FEET;
+ } else {
+ sample.depth = depth / 16.0 * FEET;
+ }
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
// Gas mix
@@ -904,8 +1016,11 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
if (parser->model == TX1) {
gasmix = data[offset] & 0x07;
have_gasmix = 1;
+ } else if (parser->model == DSX) {
+ gasmix = (data[offset] & 0xF0) >> 4;
+ have_gasmix = 1;
}
- if (have_gasmix && gasmix != gasmix_previous) {
+ if (have_gasmix && gasmix != gasmix_previous && parser->ngasmixes > 0) {
if (gasmix < 1 || gasmix > parser->ngasmixes) {
ERROR (abstract->context, "Invalid gas mix index (%u).", gasmix);
return DC_STATUS_DATAFORMAT;
@@ -935,7 +1050,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
have_deco = 1;
} else if (parser->model == ATOM31 || parser->model == VISION ||
parser->model == XPAIR || parser->model == I550 ||
- parser->model == I550C || parser->model == WISDOM4) {
+ parser->model == I550C || parser->model == WISDOM4 ||
+ parser->model == PROPLUS4 || parser->model == ATMOSAI2) {
decostop = (data[offset + 5] & 0xF0) >> 4;
decotime = array_uint16_le(data + offset + 4) & 0x03FF;
have_deco = 1;
@@ -950,11 +1066,25 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
decostop = (data[offset + 7] & 0xF0) >> 4;
decotime = array_uint16_le(data + offset + 6) & 0x0FFF;
have_deco = 1;
+ } else if (parser->model == I330R || parser->model == DSX) {
+ decostop = data[offset + 8];
+ if (decostop) {
+ // Deco time
+ decotime = array_uint16_le(data + offset + 6);
+ } else {
+ // NDL
+ decotime = array_uint16_le(data + offset + 4);
+ }
+ have_deco = 1;
}
if (have_deco) {
if (decostop) {
sample.deco.type = DC_DECO_DECOSTOP;
- sample.deco.depth = decostop * 10 * FEET;
+ if (parser->model == I330R || parser->model == DSX) {
+ sample.deco.depth = decostop * FEET;
+ } else {
+ sample.deco.depth = decostop * 10 * FEET;
+ }
} else {
sample.deco.type = DC_DECO_NDL;
sample.deco.depth = 0.0;
@@ -978,7 +1108,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
have_rbt = 1;
} else if (parser->model == VISION || parser->model == XPAIR ||
parser->model == I550 || parser->model == I550C ||
- parser->model == WISDOM4) {
+ parser->model == WISDOM4 || parser->model == PROPLUS4 ||
+ parser->model == ATMOSAI2) {
rbt = array_uint16_le(data + offset + 6) & 0x03FF;
have_rbt = 1;
}
@@ -987,6 +1118,13 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
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
unsigned int have_bookmark = 0;
if (parser->model == OC1A || parser->model == OC1B ||
diff --git a/src/oceanic_common.c b/src/oceanic_common.c
index 62f5f744..fc80bc11 100644
--- a/src/oceanic_common.c
+++ b/src/oceanic_common.c
@@ -32,72 +32,62 @@
#define VTABLE(abstract) ((const oceanic_common_device_vtable_t *) abstract->vtable)
-#define RB_LOGBOOK_DISTANCE(a,b,l) ringbuffer_distance (a, b, 1, l->rb_logbook_begin, l->rb_logbook_end)
-#define RB_LOGBOOK_INCR(a,b,l) ringbuffer_increment (a, b, l->rb_logbook_begin, l->rb_logbook_end)
+#define RB_LOGBOOK_DISTANCE(a,b,l,m) ringbuffer_distance (a, b, m, l->rb_logbook_begin, l->rb_logbook_end)
-#define RB_PROFILE_DISTANCE(a,b,l) ringbuffer_distance (a, b, 0, l->rb_profile_begin, l->rb_profile_end)
-#define RB_PROFILE_INCR(a,b,l) ringbuffer_increment (a, b, l->rb_profile_begin, l->rb_profile_end)
+#define RB_PROFILE_DISTANCE(a,b,l,m) ringbuffer_distance (a, b, m, l->rb_profile_begin, l->rb_profile_end)
#define INVALID 0
-static unsigned int
-get_profile_first (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int pagesize)
+static dc_status_t
+oceanic_common_device_get_profile (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int *begin, unsigned int *end)
{
- unsigned int value;
+ assert (layout != NULL);
+ assert (begin != NULL && end != NULL);
- if (layout->pt_mode_logbook == 0) {
- value = array_uint16_le (data + 5);
- } else if (layout->pt_mode_logbook == 1) {
- value = array_uint16_le (data + 4);
- } else if (layout->pt_mode_logbook == 3) {
- value = array_uint16_le (data + 16);
- } else {
- return array_uint16_le (data + 16);
- }
-
- 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;
-}
-
-
-static unsigned int
-get_profile_last (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int pagesize)
-{
- unsigned int value;
+ // Get the pagesize
+ unsigned int pagesize = layout->highmem ? 16 * PAGESIZE : PAGESIZE;
+ // Get the profile pointers.
+ unsigned int first = 0, last = 0;
if (layout->pt_mode_logbook == 0) {
- value = array_uint16_le (data + 6) >> 4;
+ first = array_uint16_le (data + 5);
+ last = array_uint16_le (data + 6) >> 4;
} else if (layout->pt_mode_logbook == 1) {
- value = array_uint16_le (data + 6);
- } else if (layout->pt_mode_logbook == 3) {
- value = array_uint16_le (data + 18);
- } else {
- return array_uint16_le(data + 18);
+ first = array_uint16_le (data + 4);
+ last = array_uint16_le (data + 6);
+ } else if (layout->pt_mode_logbook == 2 || layout->pt_mode_logbook == 3) {
+ first = array_uint16_le (data + 16);
+ last = array_uint16_le (data + 18);
+ } else if (layout->pt_mode_logbook == 4) {
+ first = array_uint32_le (data + 8);
+ last = array_uint32_le (data + 12);
}
- unsigned int npages = (layout->memsize - layout->highmem) / pagesize;
+ // Convert pages to bytes.
+ if (layout->pt_mode_logbook < 3) {
+ unsigned int npages = (layout->memsize - layout->highmem) / pagesize;
+ if (npages > 0x4000) {
+ first &= 0x7FFF;
+ last &= 0x7FFF;
+ } else if (npages > 0x2000) {
+ first &= 0x3FFF;
+ last &= 0x3FFF;
+ } else if (npages > 0x1000) {
+ first &= 0x1FFF;
+ last &= 0x1FFF;
+ } else {
+ first &= 0x0FFF;
+ last &= 0x0FFF;
+ }
- if (npages > 0x4000) {
- value &= 0x7FFF;
- } else if (npages > 0x2000) {
- value &= 0x3FFF;
- } else if (npages > 0x1000) {
- value &= 0x1FFF;
- } else {
- value &= 0x0FFF;
+ first *= pagesize;
+ last *= pagesize;
}
- return layout->highmem + value * pagesize;
+ *begin = layout->highmem + first;
+ *end = layout->highmem + last + (layout->pt_mode_logbook < 4 ? pagesize : 0);
+
+ return DC_STATUS_SUCCESS;
}
@@ -206,11 +196,11 @@ oceanic_common_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
return DC_STATUS_NOMEMORY;
}
- // Emit a vendor event.
- dc_event_vendor_t vendor;
- vendor.data = device->version;
- vendor.size = sizeof (device->version);
- device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
+ // Read the device info.
+ status = VTABLE(abstract)->devinfo (abstract, NULL);
+ if (status != DC_STATUS_SUCCESS) {
+ return status;
+ }
// Download the memory dump.
status = device_dump_read (abstract, 0, dc_buffer_get_data (buffer),
@@ -219,8 +209,43 @@ oceanic_common_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
return status;
}
+ return status;
+}
+
+
+dc_status_t
+oceanic_common_device_devinfo (dc_device_t *abstract, dc_event_progress_t *progress)
+{
+ dc_status_t status = DC_STATUS_SUCCESS;
+ oceanic_common_device_t *device = (oceanic_common_device_t *) abstract;
+
+ assert (device != NULL);
+ assert (device->layout != NULL);
+
+ const oceanic_common_layout_t *layout = device->layout;
+
+ // Read the device id.
+ unsigned char id[PAGESIZE] = {0};
+ status = dc_device_read (abstract, layout->cf_devinfo, id, sizeof (id));
+ if (status != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to read the memory page.");
+ return status;
+ }
+
+ // Update and emit a progress event.
+ if (progress) {
+ progress->current += PAGESIZE;
+ progress->maximum += PAGESIZE;
+ device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
+ }
+
+ // Emit a vendor event.
+ dc_event_vendor_t vendor;
+ vendor.data = device->version;
+ vendor.size = sizeof (device->version);
+ device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
+
// Emit a device info event.
- unsigned char *id = dc_buffer_get_data (buffer) + layout->cf_devinfo;
dc_event_devinfo_t devinfo;
devinfo.model = array_uint16_be (id + 8);
devinfo.firmware = device->firmware;
@@ -240,53 +265,90 @@ oceanic_common_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
dc_status_t
-oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook)
+oceanic_common_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress,
+ unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end,
+ unsigned int *rb_profile_begin, unsigned int *rb_profile_end)
{
+ dc_status_t status = DC_STATUS_SUCCESS;
oceanic_common_device_t *device = (oceanic_common_device_t *) abstract;
- dc_status_t rc = DC_STATUS_SUCCESS;
assert (device != NULL);
assert (device->layout != NULL);
- assert (device->layout->rb_logbook_entry_size <= sizeof (device->fingerprint));
- assert (progress != 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;
- // Erase the buffer.
- if (!dc_buffer_clear (logbook))
- return DC_STATUS_NOMEMORY;
-
- // For devices without a logbook ringbuffer, downloading dives isn't
- // possible. This is not considered a fatal error, but handled as if there
- // are no dives present.
- if (layout->rb_logbook_begin == layout->rb_logbook_end) {
- return DC_STATUS_SUCCESS;
- }
-
// Read the pointer data.
unsigned char pointers[PAGESIZE] = {0};
- rc = dc_device_read (abstract, layout->cf_pointers, pointers, sizeof (pointers));
- if (rc != DC_STATUS_SUCCESS) {
+ 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 rc;
+ return status;
}
- // Get the logbook pointers.
+ // 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);
- if (rb_logbook_last < layout->rb_logbook_begin ||
- rb_logbook_last >= layout->rb_logbook_end)
+ unsigned int rb_profile_first = array_uint16_le (pointers + 8);
+ unsigned int rb_profile_last = array_uint16_le (pointers + 10);
+
+ *rb_logbook_begin = rb_logbook_first;
+ *rb_logbook_end = rb_logbook_last + (layout->pt_mode_global == 0 ? layout->rb_logbook_entry_size : 0);
+ *rb_profile_begin = rb_profile_first;
+ *rb_profile_end = rb_profile_last;
+
+ return status;
+}
+
+dc_status_t
+oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end)
+{
+ oceanic_common_device_t *device = (oceanic_common_device_t *) abstract;
+ dc_status_t rc = DC_STATUS_SUCCESS;
+
+ assert (device != NULL);
+ assert (device->layout != NULL);
+ assert (device->layout->rb_logbook_entry_size <= sizeof (device->fingerprint));
+ assert (progress != NULL);
+
+ const oceanic_common_layout_t *layout = device->layout;
+
+ // Erase the buffer.
+ if (!dc_buffer_clear (logbook))
+ return DC_STATUS_NOMEMORY;
+
+ // Validate the logbook pointers.
+ unsigned int rb_logbook_begin = begin;
+ unsigned int rb_logbook_end = end;
+ if (rb_logbook_begin < layout->rb_logbook_begin ||
+ rb_logbook_begin > layout->rb_logbook_end)
{
- ERROR (abstract->context, "Invalid logbook end pointer detected (0x%04x).", rb_logbook_last);
- return DC_STATUS_DATAFORMAT;
+ ERROR (abstract->context, "Invalid logbook begin pointer detected (0x%04x).", rb_logbook_begin);
+ if (layout->rb_logbook_direction == 0) {
+ return DC_STATUS_DATAFORMAT;
+ }
+ // Fall back to downloading the entire logbook ringbuffer as
+ // workaround for an invalid logbook begin pointer!
+ rb_logbook_begin = rb_logbook_end;
}
-
- // Calculate the end pointer.
- unsigned int rb_logbook_end = 0;
- if (layout->pt_mode_global == 0) {
- rb_logbook_end = RB_LOGBOOK_INCR (rb_logbook_last, layout->rb_logbook_entry_size, layout);
- } else {
- rb_logbook_end = rb_logbook_last;
+ if (rb_logbook_end < layout->rb_logbook_begin ||
+ rb_logbook_end > layout->rb_logbook_end)
+ {
+ ERROR (abstract->context, "Invalid logbook end pointer detected (0x%04x).", rb_logbook_end);
+ if (layout->rb_logbook_direction != 0) {
+ return DC_STATUS_DATAFORMAT;
+ }
+ // Fall back to downloading the entire logbook ringbuffer as
+ // workaround for an invalid logbook end pointer!
+ rb_logbook_end = rb_logbook_begin;
}
// Calculate the number of bytes.
@@ -295,21 +357,9 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr
// full ringbuffer. We always consider the ringbuffer full in that
// case, because an empty ringbuffer can be detected by inspecting
// the logbook entries once they are downloaded.
- unsigned int rb_logbook_size = 0;
- if (rb_logbook_first < layout->rb_logbook_begin ||
- rb_logbook_first >= layout->rb_logbook_end)
- {
- // Fall back to downloading the entire logbook ringbuffer as
- // workaround for an invalid logbook begin pointer!
- ERROR (abstract->context, "Invalid logbook begin pointer detected (0x%04x).", rb_logbook_first);
- rb_logbook_size = layout->rb_logbook_end - layout->rb_logbook_begin;
- } else {
- rb_logbook_size = RB_LOGBOOK_DISTANCE (rb_logbook_first, rb_logbook_end, layout);
- }
+ unsigned int rb_logbook_size = RB_LOGBOOK_DISTANCE (rb_logbook_begin, rb_logbook_end, layout, DC_RINGBUFFER_FULL);
// Update and emit a progress event.
- progress->current += PAGESIZE;
- progress->maximum += PAGESIZE;
progress->maximum -= (layout->rb_logbook_end - layout->rb_logbook_begin) - rb_logbook_size;
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
@@ -327,7 +377,11 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr
// Create the ringbuffer stream.
dc_rbstream_t *rbstream = NULL;
- rc = dc_rbstream_new (&rbstream, abstract, PAGESIZE, PAGESIZE * device->multipage, layout->rb_logbook_begin, layout->rb_logbook_end, rb_logbook_end);
+ rc = dc_rbstream_new (&rbstream, abstract,
+ PAGESIZE, PAGESIZE * device->multipage,
+ layout->rb_logbook_begin, layout->rb_logbook_end,
+ layout->rb_logbook_direction ? rb_logbook_end : rb_logbook_begin,
+ layout->rb_logbook_direction ? DC_RBSTREAM_BACKWARD : DC_RBSTREAM_FORWARD);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
return rc;
@@ -403,9 +457,6 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
const oceanic_common_layout_t *layout = device->layout;
- // Get the pagesize
- unsigned int pagesize = layout->highmem ? 16 * PAGESIZE : PAGESIZE;
-
// Cache the logbook pointer and size.
const unsigned char *logbooks = dc_buffer_get_data (logbook);
unsigned int rb_logbook_size = dc_buffer_get_size (logbook);
@@ -413,6 +464,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
// Go through the logbook entries a first time, to get the end of
// profile pointer and calculate the total amount of bytes in the
// profile ringbuffer.
+ unsigned int rb_profile_begin = INVALID;
unsigned int rb_profile_end = INVALID;
unsigned int rb_profile_size = 0;
@@ -434,22 +486,20 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
}
// Get the profile pointers.
- unsigned int rb_entry_first = get_profile_first (logbooks + entry, layout, pagesize);
- unsigned int rb_entry_last = get_profile_last (logbooks + entry, layout, pagesize);
- if (rb_entry_first < layout->rb_profile_begin ||
- rb_entry_first >= layout->rb_profile_end ||
- rb_entry_last < layout->rb_profile_begin ||
- rb_entry_last >= layout->rb_profile_end)
+ unsigned int rb_entry_begin = 0, rb_entry_end = 0;
+ oceanic_common_device_get_profile (logbooks + entry, layout, &rb_entry_begin, &rb_entry_end);
+ if (rb_entry_begin < layout->rb_profile_begin ||
+ rb_entry_begin > layout->rb_profile_end ||
+ rb_entry_end < layout->rb_profile_begin ||
+ rb_entry_end > layout->rb_profile_end)
{
ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).",
- rb_entry_first, rb_entry_last);
+ rb_entry_begin, rb_entry_end);
status = DC_STATUS_DATAFORMAT;
continue;
}
- // Calculate the end pointer and the number of bytes.
- unsigned int rb_entry_end = RB_PROFILE_INCR (rb_entry_last, pagesize, layout);
- unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_first, rb_entry_last, layout) + pagesize;
+ DEBUG (abstract->context, "Entry: %08x %08x", rb_entry_begin, rb_entry_end);
// Take the end pointer of the most recent logbook entry as the
// end of profile pointer.
@@ -457,11 +507,13 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
rb_profile_end = previous = rb_entry_end;
}
+ // Calculate the number of bytes.
+ unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_begin, rb_entry_end, layout, DC_RINGBUFFER_FULL);
+
// Skip gaps between the profiles.
- unsigned int gap = 0;
- if (rb_entry_end != previous) {
- WARNING (abstract->context, "Profiles are not continuous.");
- gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout);
+ unsigned int gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout, DC_RINGBUFFER_EMPTY);
+ if (gap) {
+ WARNING (abstract->context, "Profiles are not continuous (%u bytes).", gap);
}
// Make sure the profile size is valid.
@@ -470,13 +522,18 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
break;
}
+ // Update the profile begin pointer.
+ rb_profile_begin = rb_entry_begin;
+
// Update the total profile size.
rb_profile_size += rb_entry_size + gap;
remaining -= rb_entry_size + gap;
- previous = rb_entry_first;
+ previous = rb_entry_begin;
}
+ DEBUG (abstract->context, "Profile: %08x %08x", rb_profile_begin, rb_profile_end);
+
// At this point, we know the exact amount of data
// that needs to be transfered for the profiles.
progress->maximum -= (layout->rb_profile_end - layout->rb_profile_begin) - rb_profile_size;
@@ -489,7 +546,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
// Create the ringbuffer stream.
dc_rbstream_t *rbstream = NULL;
- rc = dc_rbstream_new (&rbstream, abstract, PAGESIZE, PAGESIZE * device->multipage, layout->rb_profile_begin, layout->rb_profile_end, rb_profile_end);
+ rc = dc_rbstream_new (&rbstream, abstract, PAGESIZE, PAGESIZE * device->multipage, layout->rb_profile_begin, layout->rb_profile_end, rb_profile_end, DC_RBSTREAM_BACKWARD);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
return rc;
@@ -524,28 +581,28 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
}
// Get the profile pointers.
- unsigned int rb_entry_first = get_profile_first (logbooks + entry, layout, pagesize);
- unsigned int rb_entry_last = get_profile_last (logbooks + entry, layout, pagesize);
- if (rb_entry_first < layout->rb_profile_begin ||
- rb_entry_first >= layout->rb_profile_end ||
- rb_entry_last < layout->rb_profile_begin ||
- rb_entry_last >= layout->rb_profile_end)
+ unsigned int rb_entry_begin = 0, rb_entry_end = 0;
+ oceanic_common_device_get_profile (logbooks + entry, layout, &rb_entry_begin, &rb_entry_end);
+ if (rb_entry_begin < layout->rb_profile_begin ||
+ rb_entry_begin > layout->rb_profile_end ||
+ rb_entry_end < layout->rb_profile_begin ||
+ rb_entry_end > layout->rb_profile_end)
{
ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).",
- rb_entry_first, rb_entry_last);
+ rb_entry_begin, rb_entry_end);
status = DC_STATUS_DATAFORMAT;
continue;
}
- // Calculate the end pointer and the number of bytes.
- unsigned int rb_entry_end = RB_PROFILE_INCR (rb_entry_last, pagesize, layout);
- unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_first, rb_entry_last, layout) + pagesize;
+ DEBUG (abstract->context, "Entry: %08x %08x", rb_entry_begin, rb_entry_end);
+
+ // Calculate the number of bytes.
+ unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_begin, rb_entry_end, layout, DC_RINGBUFFER_FULL);
// Skip gaps between the profiles.
- unsigned int gap = 0;
- if (rb_entry_end != previous) {
- WARNING (abstract->context, "Profiles are not continuous.");
- gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout);
+ unsigned int gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout, DC_RINGBUFFER_EMPTY);
+ if (gap) {
+ WARNING (abstract->context, "Profiles are not continuous (%u bytes).", gap);
}
// Make sure the profile size is valid.
@@ -566,7 +623,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
}
remaining -= rb_entry_size + gap;
- previous = rb_entry_first;
+ previous = rb_entry_begin;
// Prepend the logbook entry to the profile data. The memory buffer is
// large enough to store this entry.
@@ -604,6 +661,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
dc_status_t
oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
{
+ dc_status_t rc = DC_STATUS_SUCCESS;
oceanic_common_device_t *device = (oceanic_common_device_t *) abstract;
assert (device != NULL);
@@ -611,45 +669,37 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
const oceanic_common_layout_t *layout = device->layout;
+ // For devices without a logbook and profile ringbuffer, downloading dives
+ // isn't possible. This is not considered a fatal error, but handled as if
+ // there are no dives present.
+ if (layout->rb_logbook_begin == layout->rb_logbook_end &&
+ layout->rb_profile_begin == layout->rb_profile_end) {
+ return DC_STATUS_SUCCESS;
+ }
+
// Enable progress notifications.
dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
- progress.maximum = PAGESIZE +
+ progress.maximum =
(layout->rb_logbook_end - layout->rb_logbook_begin) +
(layout->rb_profile_end - layout->rb_profile_begin);
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
- // Emit a vendor event.
- dc_event_vendor_t vendor;
- vendor.data = device->version;
- vendor.size = sizeof (device->version);
- device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
-
- // Read the device id.
- unsigned char id[PAGESIZE] = {0};
- dc_status_t rc = dc_device_read (abstract, layout->cf_devinfo, id, sizeof (id));
+ // Read the device info.
+ rc = VTABLE(abstract)->devinfo (abstract, &progress);
if (rc != DC_STATUS_SUCCESS) {
- ERROR (abstract->context, "Failed to read the memory page.");
return rc;
}
- // Update and emit a progress event.
- progress.current += PAGESIZE;
- device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
+ // Read the ringbuffer pointers.
+ unsigned int rb_logbook_begin = 0, rb_logbook_end = 0;
+ unsigned int rb_profile_begin = 0, rb_profile_end = 0;
+ rc = VTABLE(abstract)->pointers (abstract, &progress, &rb_logbook_begin, &rb_logbook_end, &rb_profile_begin, &rb_profile_end);
+ if (rc != DC_STATUS_SUCCESS) {
+ return rc;
+ }
- // Emit a device info event.
- dc_event_devinfo_t devinfo;
- devinfo.model = array_uint16_be (id + 8);
- devinfo.firmware = device->firmware;
- if (layout->pt_mode_serial == 0)
- devinfo.serial = array_convert_bcd2dec (id + 10, 3);
- else if (layout->pt_mode_serial == 1)
- devinfo.serial = array_convert_bin2dec (id + 11, 3);
- else
- devinfo.serial =
- (id[11] & 0x0F) * 100000 + ((id[11] & 0xF0) >> 4) * 10000 +
- (id[12] & 0x0F) * 1000 + ((id[12] & 0xF0) >> 4) * 100 +
- (id[13] & 0x0F) * 10 + ((id[13] & 0xF0) >> 4) * 1;
- device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
+ DEBUG (abstract->context, "Logbook: %08x %08x", rb_logbook_begin, rb_logbook_end);
+ DEBUG (abstract->context, "Profile: %08x %08x", rb_profile_begin, rb_profile_end);
// Memory buffer for the logbook data.
dc_buffer_t *logbook = dc_buffer_new (0);
@@ -658,7 +708,7 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
}
// Download the logbook ringbuffer.
- rc = VTABLE(abstract)->logbook (abstract, &progress, logbook);
+ rc = VTABLE(abstract)->logbook (abstract, &progress, logbook, rb_logbook_begin, rb_logbook_end);
if (rc != DC_STATUS_SUCCESS) {
dc_buffer_free (logbook);
return rc;
diff --git a/src/oceanic_common.h b/src/oceanic_common.h
index 045dca41..43254a96 100644
--- a/src/oceanic_common.h
+++ b/src/oceanic_common.h
@@ -125,8 +125,12 @@ extern "C" {
#define I200CV2 0x4749
#define GEOAIR 0x474B
+// i330r
+#define DSX 0x4741
+#define I330R 0x4744
+
#define PAGESIZE 0x10
-#define FPMAXSIZE 0x20
+#define FPMAXSIZE 0x200
#define OCEANIC_COMMON_MATCH(version,patterns,firmware) \
oceanic_common_match ((version), (patterns), \
@@ -144,6 +148,7 @@ typedef struct oceanic_common_layout_t {
unsigned int rb_logbook_begin;
unsigned int rb_logbook_end;
unsigned int rb_logbook_entry_size;
+ unsigned int rb_logbook_direction;
// Profile ringbuffer
unsigned int rb_profile_begin;
unsigned int rb_profile_end;
@@ -168,7 +173,9 @@ typedef struct oceanic_common_device_t {
typedef struct oceanic_common_device_vtable_t {
dc_device_vtable_t base;
- dc_status_t (*logbook) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook);
+ dc_status_t (*devinfo) (dc_device_t *device, dc_event_progress_t *progress);
+ dc_status_t (*pointers) (dc_device_t *device, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end);
+ dc_status_t (*logbook) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end);
dc_status_t (*profile) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata);
} oceanic_common_device_vtable_t;
@@ -186,7 +193,15 @@ void
oceanic_common_device_init (oceanic_common_device_t *device);
dc_status_t
-oceanic_common_device_logbook (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook);
+oceanic_common_device_devinfo (dc_device_t *device, dc_event_progress_t *progress);
+
+dc_status_t
+oceanic_common_device_pointers (dc_device_t *device, dc_event_progress_t *progress,
+ unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end,
+ unsigned int *rb_profile_begin, unsigned int *rb_profile_end);
+
+dc_status_t
+oceanic_common_device_logbook (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end);
dc_status_t
oceanic_common_device_profile (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata);
diff --git a/src/oceanic_veo250.c b/src/oceanic_veo250.c
index 58a9ceb3..f39b1cdb 100644
--- a/src/oceanic_veo250.c
+++ b/src/oceanic_veo250.c
@@ -58,6 +58,8 @@ static const oceanic_common_device_vtable_t oceanic_veo250_device_vtable = {
NULL, /* timesync */
oceanic_veo250_device_close /* close */
},
+ oceanic_common_device_devinfo,
+ oceanic_common_device_pointers,
oceanic_common_device_logbook,
oceanic_common_device_profile,
};
@@ -70,6 +72,7 @@ static const oceanic_common_layout_t oceanic_veo250_layout = {
0x0400, /* rb_logbook_begin */
0x0600, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0600, /* rb_profile_begin */
0x8000, /* rb_profile_end */
1, /* pt_mode_global */
diff --git a/src/oceanic_vtpro.c b/src/oceanic_vtpro.c
index ef3d6d16..b63c0fb4 100644
--- a/src/oceanic_vtpro.c
+++ b/src/oceanic_vtpro.c
@@ -51,7 +51,8 @@ typedef struct oceanic_vtpro_device_t {
oceanic_vtpro_protocol_t protocol;
} oceanic_vtpro_device_t;
-static dc_status_t oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook);
+static dc_status_t oceanic_vtpro_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end);
+static dc_status_t oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end);
static dc_status_t oceanic_vtpro_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size);
static dc_status_t oceanic_vtpro_device_close (dc_device_t *abstract);
@@ -67,6 +68,8 @@ static const oceanic_common_device_vtable_t oceanic_vtpro_device_vtable = {
NULL, /* timesync */
oceanic_vtpro_device_close /* close */
},
+ oceanic_common_device_devinfo,
+ oceanic_vtpro_device_pointers,
oceanic_vtpro_device_logbook,
oceanic_common_device_profile,
};
@@ -79,6 +82,7 @@ static const oceanic_common_layout_t oceanic_vtpro_layout = {
0x0240, /* rb_logbook_begin */
0x0440, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x0440, /* rb_profile_begin */
0x8000, /* rb_profile_end */
0, /* pt_mode_global */
@@ -94,6 +98,7 @@ static const oceanic_common_layout_t oceanic_wisdom_layout = {
0x03D0, /* rb_logbook_begin */
0x05D0, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x05D0, /* rb_profile_begin */
0x8000, /* rb_profile_end */
0, /* pt_mode_global */
@@ -109,6 +114,7 @@ static const oceanic_common_layout_t aeris_500ai_layout = {
0x0200, /* rb_logbook_begin */
0x0200, /* rb_logbook_end */
8, /* rb_logbook_entry_size */
+ 1, /* rb_logbook_direction */
0x00200, /* rb_profile_begin */
0x20000, /* rb_profile_end */
0, /* pt_mode_global */
@@ -286,7 +292,49 @@ oceanic_vtpro_calibrate (oceanic_vtpro_device_t *device)
}
static dc_status_t
-oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook)
+oceanic_aeris500ai_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end)
+{
+ dc_status_t status = DC_STATUS_SUCCESS;
+ oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract;
+
+ assert (device != NULL);
+ assert (device->base.layout != NULL);
+ assert (rb_logbook_begin != NULL && rb_logbook_end != NULL);
+ assert (rb_profile_begin != NULL && rb_profile_end != NULL);
+
+ const oceanic_common_layout_t *layout = device->base.layout;
+
+ // Read the pointer data.
+ unsigned char pointers[PAGESIZE] = {0};
+ status = oceanic_vtpro_device_read (abstract, layout->cf_pointers, pointers, sizeof (pointers));
+ if (status != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to read the memory page.");
+ return status;
+ }
+
+ // Update and emit a progress event.
+ if (progress) {
+ progress->current += PAGESIZE;
+ progress->maximum += PAGESIZE;
+ device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
+ }
+
+ // Get the pointers.
+ unsigned int rb_logbook_first = pointers[0x02];
+ unsigned int rb_logbook_last = pointers[0x03];
+ unsigned int rb_profile_first = array_uint16_le (pointers + 4) * PAGESIZE;
+ unsigned int rb_profile_last = array_uint16_le (pointers + 6) * PAGESIZE;
+
+ *rb_logbook_begin = rb_logbook_first;
+ *rb_logbook_end = rb_logbook_last;
+ *rb_profile_begin = rb_profile_first;
+ *rb_profile_end = rb_profile_last;
+
+ return status;
+}
+
+static dc_status_t
+oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end)
{
dc_status_t rc = DC_STATUS_SUCCESS;
oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract;
@@ -297,36 +345,25 @@ oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *p
assert (device->base.layout->rb_logbook_begin == device->base.layout->rb_logbook_end);
assert (progress != NULL);
- const oceanic_common_layout_t *layout = device->base.layout;
-
// Erase the buffer.
if (!dc_buffer_clear (logbook))
return DC_STATUS_NOMEMORY;
- // Read the pointer data.
- unsigned char pointers[PAGESIZE] = {0};
- rc = oceanic_vtpro_device_read (abstract, layout->cf_pointers, pointers, sizeof (pointers));
- if (rc != DC_STATUS_SUCCESS) {
- ERROR (abstract->context, "Failed to read the memory page.");
- return rc;
- }
-
- // Get the logbook pointers.
- unsigned int last = pointers[0x03];
+ // Get the number of dives.
+ unsigned int ndives = end - begin + 1;
// Update and emit a progress event.
- progress->current += PAGESIZE;
- progress->maximum += PAGESIZE + (last + 1) * PAGESIZE / 2;
+ progress->maximum += ndives * PAGESIZE / 2;
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
// Allocate memory for the logbook entries.
- if (!dc_buffer_reserve (logbook, (last + 1) * PAGESIZE / 2))
+ if (!dc_buffer_reserve (logbook, ndives * PAGESIZE / 2))
return DC_STATUS_NOMEMORY;
// Send the logbook index command.
unsigned char command[] = {0x52,
- (last >> 8) & 0xFF, // high
- (last ) & 0xFF, // low
+ begin & 0xFF,
+ end & 0xFF,
0x00};
rc = oceanic_vtpro_transfer (device, command, sizeof (command), NULL, 0);
if (rc != DC_STATUS_SUCCESS) {
@@ -335,7 +372,7 @@ oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *p
}
// Read the logbook index.
- for (unsigned int i = 0; i < last + 1; ++i) {
+ for (unsigned int i = 0; i < ndives; ++i) {
// Receive the answer of the dive computer.
unsigned char answer[PAGESIZE / 2 + 1] = {0};
rc = dc_iostream_read (device->iostream, answer, sizeof(answer), NULL);
@@ -374,14 +411,26 @@ oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *p
}
static dc_status_t
-oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook)
+oceanic_vtpro_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end)
+{
+ oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract;
+
+ if (device->base.model == AERIS500AI) {
+ return oceanic_aeris500ai_device_pointers (abstract, progress, rb_logbook_begin, rb_logbook_end, rb_profile_begin, rb_profile_end);
+ } else {
+ return oceanic_common_device_pointers (abstract, progress, rb_logbook_begin, rb_logbook_end, rb_profile_begin, rb_profile_end);
+ }
+}
+
+static dc_status_t
+oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end)
{
oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract;
if (device->base.model == AERIS500AI) {
- return oceanic_aeris500ai_device_logbook (abstract, progress, logbook);
+ return oceanic_aeris500ai_device_logbook (abstract, progress, logbook, begin, end);
} else {
- return oceanic_common_device_logbook (abstract, progress, logbook);
+ return oceanic_common_device_logbook (abstract, progress, logbook, begin, end);
}
}
diff --git a/src/parser.c b/src/parser.c
index d63c5c67..ba78399d 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -127,6 +127,7 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, const unsigned
rc = oceanic_veo250_parser_create (&parser, context, data, size, model);
break;
case DC_FAMILY_OCEANIC_ATOM2:
+ case DC_FAMILY_PELAGIC_I330R:
if (model == REACTPROWHITE)
rc = oceanic_veo250_parser_create (&parser, context, data, size, model);
else
diff --git a/src/pelagic_i330r.c b/src/pelagic_i330r.c
new file mode 100644
index 00000000..17aad3bf
--- /dev/null
+++ b/src/pelagic_i330r.c
@@ -0,0 +1,646 @@
+/*
+ * libdivecomputer
+ *
+ * Copyright (C) 2023 Janice McLaughlin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include // memcpy
+#include // malloc, free
+#include
+
+#include
+
+#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;
+}
diff --git a/src/pelagic_i330r.h b/src/pelagic_i330r.h
new file mode 100644
index 00000000..23045cdf
--- /dev/null
+++ b/src/pelagic_i330r.h
@@ -0,0 +1,40 @@
+/*
+ * 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
+ */
+
+#ifndef PELAGIC_I330R_H
+#define PELAGIC_I330R_H
+
+#include
+#include
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+dc_status_t
+pelagic_i330r_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PELAGIC_I330R_H */
diff --git a/src/rbstream.c b/src/rbstream.c
index 07188e0f..f4da2d7a 100644
--- a/src/rbstream.c
+++ b/src/rbstream.c
@@ -28,11 +28,13 @@
struct dc_rbstream_t {
dc_device_t *device;
+ dc_rbstream_direction_t direction;
unsigned int pagesize;
unsigned int packetsize;
unsigned int begin;
unsigned int end;
unsigned int address;
+ unsigned int offset;
unsigned int available;
unsigned int skip;
unsigned char cache[];
@@ -53,7 +55,7 @@ iceil (unsigned int x, unsigned int n)
}
dc_status_t
-dc_rbstream_new (dc_rbstream_t **out, dc_device_t *device, unsigned int pagesize, unsigned int packetsize, unsigned int begin, unsigned int end, unsigned int address)
+dc_rbstream_new (dc_rbstream_t **out, dc_device_t *device, unsigned int pagesize, unsigned int packetsize, unsigned int begin, unsigned int end, unsigned int address, dc_rbstream_direction_t direction)
{
dc_rbstream_t *rbstream = NULL;
@@ -78,6 +80,18 @@ dc_rbstream_new (dc_rbstream_t **out, dc_device_t *device, unsigned int pagesize
return DC_STATUS_INVALIDARGS;
}
+ // Ringbuffer boundaries should not be reversed.
+ if (begin > end) {
+ ERROR (device->context, "Ringbuffer boundaries reversed!");
+ return DC_STATUS_INVALIDARGS;
+ }
+
+ // Packet size should be smaller than the ringbuffer size.
+ if (packetsize > (end - begin)) {
+ ERROR (device->context, "Packet size larger than the ringbuffer size!");
+ return DC_STATUS_INVALIDARGS;
+ }
+
// Address should be inside the ringbuffer.
if (address < begin || address > end) {
ERROR (device->context, "Address outside the ringbuffer!");
@@ -92,64 +106,64 @@ dc_rbstream_new (dc_rbstream_t **out, dc_device_t *device, unsigned int pagesize
}
rbstream->device = device;
+ rbstream->direction = direction;
rbstream->pagesize = pagesize;
rbstream->packetsize = packetsize;
rbstream->begin = begin;
rbstream->end = end;
- rbstream->address = iceil(address, pagesize);
+ if (direction == DC_RBSTREAM_FORWARD) {
+ rbstream->address = ifloor(address, pagesize);
+ rbstream->skip = address - rbstream->address;
+ } else {
+ rbstream->address = iceil(address, pagesize);
+ rbstream->skip = rbstream->address - address;
+ }
+ rbstream->offset = 0;
rbstream->available = 0;
- rbstream->skip = rbstream->address - address;
*out = rbstream;
return DC_STATUS_SUCCESS;
}
-dc_status_t
-dc_rbstream_read (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsigned char data[], unsigned int size)
+static dc_status_t
+dc_rbstream_read_backward (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsigned char data[], unsigned int size)
{
dc_status_t rc = DC_STATUS_SUCCESS;
- if (rbstream == NULL)
- return DC_STATUS_INVALIDARGS;
-
- unsigned int address = rbstream->address;
- unsigned int available = rbstream->available;
- unsigned int skip = rbstream->skip;
-
unsigned int nbytes = 0;
unsigned int offset = size;
while (nbytes < size) {
- if (available == 0) {
+ if (rbstream->available == 0) {
// Handle the ringbuffer wrap point.
- if (address == rbstream->begin)
- address = rbstream->end;
+ if (rbstream->address == rbstream->begin)
+ rbstream->address = rbstream->end;
// Calculate the packet size.
unsigned int len = rbstream->packetsize;
- if (rbstream->begin + len > address)
- len = address - rbstream->begin;
-
- // Move to the begin of the current packet.
- address -= len;
+ if (rbstream->begin + len > rbstream->address)
+ len = rbstream->address - rbstream->begin;
// Read the packet into the cache.
- rc = dc_device_read (rbstream->device, address, rbstream->cache, rbstream->packetsize);
+ rc = dc_device_read (rbstream->device, rbstream->address - len, rbstream->cache, rbstream->packetsize);
if (rc != DC_STATUS_SUCCESS)
return rc;
- available = len - skip;
- skip = 0;
+ // Move to the end of the next packet.
+ rbstream->address -= len;
+
+ rbstream->available = len - rbstream->skip;
+ rbstream->skip = 0;
}
- unsigned int length = available;
+ unsigned int length = rbstream->available;
if (nbytes + length > size)
length = size - nbytes;
offset -= length;
- available -= length;
+ rbstream->available -= length;
- memcpy (data + offset, rbstream->cache + available, length);
+ memcpy (data + offset, rbstream->cache + rbstream->available, length);
// Update and emit a progress event.
if (progress) {
@@ -160,13 +174,76 @@ dc_rbstream_read (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsign
nbytes += length;
}
- rbstream->address = address;
- rbstream->available = available;
- rbstream->skip = skip;
+ return rc;
+}
+
+static dc_status_t
+dc_rbstream_read_forward (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsigned char data[], unsigned int size)
+{
+ dc_status_t rc = DC_STATUS_SUCCESS;
+
+ unsigned int nbytes = 0;
+ while (nbytes < size) {
+ if (rbstream->available == 0) {
+ // Handle the ringbuffer wrap point.
+ if (rbstream->address == rbstream->end)
+ rbstream->address = rbstream->begin;
+
+ // Calculate the packet size.
+ unsigned int len = rbstream->packetsize;
+ if (rbstream->address + len > rbstream->end)
+ len = rbstream->end - rbstream->address;
+
+ // Calculate the excess number of bytes.
+ unsigned int extra = rbstream->packetsize - len;
+
+ // Read the packet into the cache.
+ rc = dc_device_read (rbstream->device, rbstream->address - extra, rbstream->cache, rbstream->packetsize);
+ if (rc != DC_STATUS_SUCCESS)
+ return rc;
+
+ // Move to the begin of the next packet.
+ rbstream->address += len;
+
+ rbstream->offset = extra + rbstream->skip;
+ rbstream->available = len - rbstream->skip;
+ rbstream->skip = 0;
+ }
+
+ unsigned int length = rbstream->available;
+ if (nbytes + length > size)
+ length = size - nbytes;
+
+ memcpy (data + nbytes, rbstream->cache + rbstream->offset, length);
+
+ rbstream->offset += length;
+ rbstream->available -= length;
+
+ // Update and emit a progress event.
+ if (progress) {
+ progress->current += length;
+ device_event_emit (rbstream->device, DC_EVENT_PROGRESS, progress);
+ }
+
+ nbytes += length;
+ }
return rc;
}
+dc_status_t
+dc_rbstream_read (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsigned char data[], unsigned int size)
+{
+ if (rbstream == NULL)
+ return DC_STATUS_INVALIDARGS;
+
+ if (rbstream->direction == DC_RBSTREAM_FORWARD) {
+ return dc_rbstream_read_forward (rbstream, progress, data, size);
+ } else {
+ return dc_rbstream_read_backward (rbstream, progress, data, size);
+ }
+}
+
dc_status_t
dc_rbstream_free (dc_rbstream_t *rbstream)
{
diff --git a/src/rbstream.h b/src/rbstream.h
index be1d8f6d..2ea07674 100644
--- a/src/rbstream.h
+++ b/src/rbstream.h
@@ -33,6 +33,14 @@ extern "C" {
*/
typedef struct dc_rbstream_t dc_rbstream_t;
+/**
+ * The ringbuffer read direction.
+ */
+typedef enum dc_rbstream_direction_t {
+ DC_RBSTREAM_FORWARD,
+ DC_RBSTREAM_BACKWARD
+} dc_rbstream_direction_t;
+
/**
* Create a new ringbuffer stream.
*
@@ -43,11 +51,12 @@ typedef struct dc_rbstream_t dc_rbstream_t;
* @param[in] begin The ringbuffer begin address.
* @param[in] end The ringbuffer end address.
* @param[in] address The stream start address.
+ * @param[in] direction The ringbuffer read direction.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
-dc_rbstream_new (dc_rbstream_t **rbstream, dc_device_t *device, unsigned int pagesize, unsigned int packetsize, unsigned int begin, unsigned int end, unsigned int address);
+dc_rbstream_new (dc_rbstream_t **rbstream, dc_device_t *device, unsigned int pagesize, unsigned int packetsize, unsigned int begin, unsigned int end, unsigned int address, dc_rbstream_direction_t direction);
/**
* Read data from the ringbuffer stream.
diff --git a/src/ringbuffer.c b/src/ringbuffer.c
index 72318d06..bea496dd 100644
--- a/src/ringbuffer.c
+++ b/src/ringbuffer.c
@@ -25,39 +25,43 @@
static unsigned int
-normalize (unsigned int a, unsigned int size)
+modulo (unsigned int x, unsigned int n, unsigned int d)
{
- return a % size;
-}
-
-
-static unsigned int
-distance (unsigned int a, unsigned int b, int mode, unsigned int size)
-{
- if (a < b) {
- return (b - a) % size;
- } else if (a > b) {
- return size - (a - b) % size;
+ unsigned int result = 0;
+ if (d > x) {
+#if 0
+ result = (n - (d - x) % n) % n;
+#else
+ unsigned int m = (d - x) % n;
+ result = m ? n - m : m;
+#endif
} else {
- return (mode == 0 ? 0 : size);
+ result = (x - d) % n;
}
-}
-
-static unsigned int
-increment (unsigned int a, unsigned int delta, unsigned int size)
-{
- return (a + delta) % size;
+ return result + d;
}
static unsigned int
-decrement (unsigned int a, unsigned int delta, unsigned int size)
+distance (unsigned int a, unsigned int b, unsigned int n, unsigned int mode)
{
- if (delta <= a) {
- return (a - delta) % size;
+ unsigned int result = 0;
+ if (a > b) {
+#if 0
+ result = (n - (a - b) % n) % n;
+#else
+ unsigned int m = (a - b) % n;
+ result = m ? n - m : m;
+#endif
+ } else {
+ result = (b - a) % n;
+ }
+
+ if (result == 0) {
+ return (mode == 0 ? 0 : n);
} else {
- return size - (delta - a) % size;
+ return result;
}
}
@@ -65,38 +69,38 @@ decrement (unsigned int a, unsigned int delta, unsigned int size)
unsigned int
ringbuffer_normalize (unsigned int a, unsigned int begin, unsigned int end)
{
- assert (end >= begin);
- assert (a >= begin);
+ assert (end > begin);
- return normalize (a, end - begin);
+ unsigned int n = end - begin;
+ return modulo (a, n, begin);
}
unsigned int
ringbuffer_distance (unsigned int a, unsigned int b, int mode, unsigned int begin, unsigned int end)
{
- assert (end >= begin);
- assert (a >= begin);
+ assert (end > begin);
- return distance (a, b, mode, end - begin);
+ unsigned int n = end - begin;
+ return distance (a, b, n, mode);
}
unsigned int
ringbuffer_increment (unsigned int a, unsigned int delta, unsigned int begin, unsigned int end)
{
- assert (end >= begin);
- assert (a >= begin);
+ assert (end > begin);
- return increment (a - begin, delta, end - begin) + begin;
+ unsigned int n = end - begin;
+ return modulo (a + delta % n, n, begin);
}
unsigned int
ringbuffer_decrement (unsigned int a, unsigned int delta, unsigned int begin, unsigned int end)
{
- assert (end >= begin);
- assert (a >= begin);
+ assert (end > begin);
- return decrement (a - begin, delta, end - begin) + begin;
+ unsigned int n = end - begin;
+ return modulo (a + n - delta % n, n, begin);
}
diff --git a/src/ringbuffer.h b/src/ringbuffer.h
index 3915739b..e41cd5ac 100644
--- a/src/ringbuffer.h
+++ b/src/ringbuffer.h
@@ -26,6 +26,9 @@
extern "C" {
#endif /* __cplusplus */
+#define DC_RINGBUFFER_EMPTY 0
+#define DC_RINGBUFFER_FULL 1
+
unsigned int
ringbuffer_normalize (unsigned int a, unsigned int begin, unsigned int end);
diff --git a/src/seac_screen.c b/src/seac_screen.c
index 9b3796f8..3015fd65 100644
--- a/src/seac_screen.c
+++ b/src/seac_screen.c
@@ -58,7 +58,7 @@
#define RB_PROFILE_BEGIN 0x010000
#define RB_PROFILE_END 0x200000
#define RB_PROFILE_SIZE (RB_PROFILE_END - RB_PROFILE_BEGIN)
-#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, 1, RB_PROFILE_BEGIN, RB_PROFILE_END)
+#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_FULL, RB_PROFILE_BEGIN, RB_PROFILE_END)
#define RB_PROFILE_INCR(a,d) ringbuffer_increment (a, d, RB_PROFILE_BEGIN, RB_PROFILE_END)
typedef struct seac_screen_device_t {
@@ -546,7 +546,7 @@ seac_screen_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback,
// Create the ringbuffer stream.
dc_rbstream_t *rbstream = NULL;
- status = dc_rbstream_new (&rbstream, abstract, SZ_READ, SZ_READ, RB_PROFILE_BEGIN, RB_PROFILE_END, eop);
+ status = dc_rbstream_new (&rbstream, abstract, SZ_READ, SZ_READ, RB_PROFILE_BEGIN, RB_PROFILE_END, eop, DC_RBSTREAM_BACKWARD);
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
goto error_free_profile;
diff --git a/src/shearwater_common.c b/src/shearwater_common.c
index 1b06cefd..83527b62 100644
--- a/src/shearwater_common.c
+++ b/src/shearwater_common.c
@@ -748,6 +748,9 @@ dc_status_t shearwater_common_get_model(shearwater_common_device_t *device, unsi
case 0x1512:
*model = PEREGRINE;
break;
+ case 0x1712:
+ *model = PEREGRINE_TX;
+ break;
case 0xC0E0:
*model = TERN;
break;
diff --git a/src/shearwater_common.h b/src/shearwater_common.h
index de9e2506..de0556bf 100644
--- a/src/shearwater_common.h
+++ b/src/shearwater_common.h
@@ -58,6 +58,7 @@ extern "C" {
#define PETREL3 10
#define PERDIX2 11
#define TERN 12
+#define PEREGRINE_TX 13
#define NSTEPS 10000
#define STEP(i,n) ((NSTEPS * (i) + (n) / 2) / (n))
diff --git a/src/suunto_common.c b/src/suunto_common.c
index 9988b86a..080b5301 100644
--- a/src/suunto_common.c
+++ b/src/suunto_common.c
@@ -27,7 +27,7 @@
#include "ringbuffer.h"
#include "array.h"
-#define RB_PROFILE_DISTANCE(a,b,l) ringbuffer_distance (a, b, 0, l->rb_profile_begin, l->rb_profile_end)
+#define RB_PROFILE_DISTANCE(a,b,l) ringbuffer_distance (a, b, DC_RINGBUFFER_EMPTY, l->rb_profile_begin, l->rb_profile_end)
#define RB_PROFILE_PEEK(a,l) ringbuffer_decrement (a, l->peek, l->rb_profile_begin, l->rb_profile_end)
void
diff --git a/src/suunto_common2.c b/src/suunto_common2.c
index 063ea2b7..c26eb54e 100644
--- a/src/suunto_common2.c
+++ b/src/suunto_common2.c
@@ -297,7 +297,7 @@ suunto_common2_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%04x 0x%04x 0x%04x %u).", begin, last, end, count);
remaining = layout->rb_profile_end - layout->rb_profile_begin;
} else {
- remaining = RB_PROFILE_DISTANCE (layout, begin, end, count != 0);
+ remaining = RB_PROFILE_DISTANCE (layout, begin, end, count ? DC_RINGBUFFER_FULL : DC_RINGBUFFER_EMPTY);
}
// Update and emit a progress event.
@@ -307,7 +307,7 @@ suunto_common2_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
// Create the ringbuffer stream.
dc_rbstream_t *rbstream = NULL;
- rc = dc_rbstream_new (&rbstream, abstract, 1, SZ_PACKET, layout->rb_profile_begin, layout->rb_profile_end, end);
+ rc = dc_rbstream_new (&rbstream, abstract, 1, SZ_PACKET, layout->rb_profile_begin, layout->rb_profile_end, end, DC_RBSTREAM_BACKWARD);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
return rc;
@@ -328,7 +328,7 @@ suunto_common2_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
unsigned int offset = remaining;
while (offset) {
// Calculate the size of the current dive.
- unsigned int size = RB_PROFILE_DISTANCE (layout, current, previous, 1);
+ unsigned int size = RB_PROFILE_DISTANCE (layout, current, previous, DC_RINGBUFFER_FULL);
if (size < 4 || size > offset) {
ERROR (abstract->context, "Unexpected profile size (%u %u).", size, offset);
diff --git a/src/suunto_solution.c b/src/suunto_solution.c
index e72fe94e..e3e6b1cf 100644
--- a/src/suunto_solution.c
+++ b/src/suunto_solution.c
@@ -300,7 +300,7 @@ suunto_solution_extract_dives (dc_device_t *abstract, const unsigned char data[]
// to find the start of the current dive.
unsigned int peek = ringbuffer_increment (current, 2, RB_PROFILE_BEGIN, RB_PROFILE_END);
if (data[peek] == 0x80) {
- unsigned int len = ringbuffer_distance (previous, current, 0, RB_PROFILE_BEGIN, RB_PROFILE_END);
+ unsigned int len = ringbuffer_distance (previous, current, DC_RINGBUFFER_EMPTY, RB_PROFILE_BEGIN, RB_PROFILE_END);
if (callback && !callback (buffer + idx, len, NULL, 0, userdata))
return DC_STATUS_SUCCESS;
diff --git a/src/uwatec_aladin.c b/src/uwatec_aladin.c
index 1cfec542..ee154331 100644
--- a/src/uwatec_aladin.c
+++ b/src/uwatec_aladin.c
@@ -36,7 +36,7 @@
#define RB_PROFILE_BEGIN 0x000
#define RB_PROFILE_END 0x600
#define RB_PROFILE_NEXT(a) ringbuffer_increment (a, 1, RB_PROFILE_BEGIN, RB_PROFILE_END)
-#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, 0, RB_PROFILE_BEGIN, RB_PROFILE_END)
+#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_EMPTY, RB_PROFILE_BEGIN, RB_PROFILE_END)
#define HEADER 4
diff --git a/src/uwatec_smart.c b/src/uwatec_smart.c
index e0d34c1b..981efc5e 100644
--- a/src/uwatec_smart.c
+++ b/src/uwatec_smart.c
@@ -31,7 +31,8 @@
#define ISINSTANCE(device) dc_device_isinstance((device), &uwatec_smart_device_vtable)
-#define DATASIZE 254
+#define DATASIZE_RX 255
+#define DATASIZE_TX 254
#define MAX_PACKETSIZE 256
#define PACKETSIZE_USBHID_RX 64
#define PACKETSIZE_USBHID_TX 32
@@ -90,13 +91,13 @@ uwatec_smart_irda_send (uwatec_smart_device_t *device, unsigned char cmd, const
dc_status_t rc = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device;
- if (size > DATASIZE) {
+ if (size > DATASIZE_TX) {
ERROR (abstract->context, "Command too large (" DC_PRINTF_SIZE ").", size);
return DC_STATUS_PROTOCOL;
}
// Build the packet.
- unsigned char packet[1 + DATASIZE] = {
+ unsigned char packet[1 + DATASIZE_TX] = {
cmd};
if (size) {
memcpy (packet + 1, data, size);
@@ -157,13 +158,13 @@ uwatec_smart_serial_send (uwatec_smart_device_t *device, unsigned char cmd, cons
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device;
- if (size > DATASIZE) {
+ if (size > DATASIZE_TX) {
ERROR (abstract->context, "Command too large (" DC_PRINTF_SIZE ").", size);
return DC_STATUS_PROTOCOL;
}
// Build the packet.
- unsigned char packet[12 + DATASIZE + 1] = {
+ unsigned char packet[12 + DATASIZE_TX + 1] = {
0xFF, 0xFF, 0xFF,
0xA6, 0x59, 0xBD, 0xC2,
size + 1,
@@ -277,12 +278,12 @@ uwatec_smart_usbhid_send (uwatec_smart_device_t *device, unsigned char cmd, cons
dc_status_t rc = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device;
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
- unsigned char buf[DATASIZE + 3];
+ unsigned char buf[DATASIZE_TX + 3];
size_t packetsize = transport == DC_TRANSPORT_USBHID ?
PACKETSIZE_USBHID_TX + 1 : sizeof(buf);
- if (size > DATASIZE || size + 3 > packetsize) {
+ if (size > DATASIZE_TX || size + 3 > packetsize) {
ERROR (abstract->context, "Command too large (" DC_PRINTF_SIZE ").", size);
return DC_STATUS_INVALIDARGS;
}
@@ -316,7 +317,7 @@ uwatec_smart_usbhid_receive (uwatec_smart_device_t *device, dc_event_progress_t
dc_status_t rc = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device;
dc_transport_t transport = dc_iostream_get_transport(device->iostream);
- unsigned char buf[DATASIZE + 1];
+ unsigned char buf[DATASIZE_RX + 1];
size_t packetsize = transport == DC_TRANSPORT_USBHID ?
PACKETSIZE_USBHID_RX : sizeof(buf);
diff --git a/src/zeagle_n2ition3.c b/src/zeagle_n2ition3.c
index 420ac0c3..0d43122e 100644
--- a/src/zeagle_n2ition3.c
+++ b/src/zeagle_n2ition3.c
@@ -277,7 +277,7 @@ zeagle_n2ition3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callba
}
// Get the number of logbook items.
- unsigned int count = ringbuffer_distance (first, last, 0, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END) + 1;
+ unsigned int count = ringbuffer_distance (first, last, DC_RINGBUFFER_EMPTY, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END) + 1;
// Get the profile pointer.
unsigned int eop = array_uint16_le (config + 0x7E);
@@ -302,7 +302,7 @@ zeagle_n2ition3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callba
}
// Get the profile length.
- unsigned int length = ringbuffer_distance (current, previous, 1, RB_PROFILE_BEGIN, RB_PROFILE_END);
+ unsigned int length = ringbuffer_distance (current, previous, DC_RINGBUFFER_FULL, RB_PROFILE_BEGIN, RB_PROFILE_END);
// Check for a ringbuffer overflow.
if (total + length > RB_PROFILE_END - RB_PROFILE_BEGIN) {
@@ -326,7 +326,7 @@ zeagle_n2ition3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callba
// Create the ringbuffer stream.
dc_rbstream_t *rbstream = NULL;
- rc = dc_rbstream_new (&rbstream, abstract, 1, SZ_PACKET, RB_PROFILE_BEGIN, RB_PROFILE_END, eop);
+ rc = dc_rbstream_new (&rbstream, abstract, 1, SZ_PACKET, RB_PROFILE_BEGIN, RB_PROFILE_END, eop, DC_RBSTREAM_BACKWARD);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
return rc;
@@ -344,7 +344,7 @@ zeagle_n2ition3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callba
unsigned int current = array_uint16_le (config + 2 * idx);
// Get the profile length.
- unsigned int length = ringbuffer_distance (current, previous, 1, RB_PROFILE_BEGIN, RB_PROFILE_END);
+ unsigned int length = ringbuffer_distance (current, previous, DC_RINGBUFFER_FULL, RB_PROFILE_BEGIN, RB_PROFILE_END);
// Move to the begin of the current dive.
offset -= length;