diff --git a/include/libdivecomputer/mares_iconhd.h b/include/libdivecomputer/mares_iconhd.h
index 38f82b3..ce0c8c6 100644
--- a/include/libdivecomputer/mares_iconhd.h
+++ b/include/libdivecomputer/mares_iconhd.h
@@ -33,9 +33,6 @@ extern "C" {
dc_status_t
mares_iconhd_device_open (dc_device_t **device, dc_context_t *context, const char *name, unsigned int model);
-dc_status_t
-mares_iconhd_extract_dives (dc_device_t *device, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata);
-
dc_status_t
mares_iconhd_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int model);
diff --git a/msvc/libdivecomputer.vcproj b/msvc/libdivecomputer.vcproj
index 2f3dcdf..1e03b33 100644
--- a/msvc/libdivecomputer.vcproj
+++ b/msvc/libdivecomputer.vcproj
@@ -362,6 +362,10 @@
RelativePath="..\src\parser.c"
>
+
+
@@ -680,6 +684,10 @@
RelativePath="..\include\libdivecomputer\parser.h"
>
+
+
diff --git a/src/Makefile.am b/src/Makefile.am
index c100380..db5f742 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -62,6 +62,7 @@ libdivecomputer_la_SOURCES = \
citizen_aqualand.c citizen_aqualand_parser.c \
divesystem_idive.c divesystem_idive_parser.c \
ringbuffer.h ringbuffer.c \
+ rbstream.h rbstream.c \
checksum.h checksum.c \
array.h array.c \
buffer.c \
diff --git a/src/cressi_edy.c b/src/cressi_edy.c
index 0dbe456..9270b92 100644
--- a/src/cressi_edy.c
+++ b/src/cressi_edy.c
@@ -31,6 +31,7 @@
#include "checksum.h"
#include "array.h"
#include "ringbuffer.h"
+#include "rbstream.h"
#define ISINSTANCE(device) dc_device_isinstance((device), &cressi_edy_device_vtable)
@@ -100,20 +101,6 @@ static const cressi_edy_layout_t tusa_iq700_layout = {
0x3C, /* config */
};
-static unsigned int
-ifloor (unsigned int x, unsigned int n)
-{
- // Round down to next lower multiple.
- return (x / n) * n;
-}
-
-static unsigned int
-iceil (unsigned int x, unsigned int n)
-{
- // Round up to next higher multiple.
- return ((x + n - 1) / n) * n;
-}
-
static dc_status_t
cressi_edy_packet (cressi_edy_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, int trailer)
{
@@ -333,7 +320,10 @@ cressi_edy_device_close (dc_device_t *abstract)
dc_status_t rc = DC_STATUS_SUCCESS;
// Send the quit command.
- cressi_edy_quit (device);
+ rc = cressi_edy_quit (device);
+ if (rc != DC_STATUS_SUCCESS) {
+ dc_status_set_error(&status, rc);
+ }
// Close the device.
rc = dc_serial_close (device->port);
@@ -492,41 +482,29 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
idx--;
}
- // Because dives are not necessary aligned to packet boundaries, and
- // we always do aligned reads, there can be padding bytes present on
- // both sides of the memory buffer. These extra bytes need to be
- // included in the total length.
- total += (previous - ifloor(previous, SZ_PACKET)) +
- (iceil(eop, SZ_PACKET) - eop);
-
// Update and emit a progress event.
progress.current += SZ_PACKET;
progress.maximum = SZ_PACKET + total;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
+ // 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);
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to create the ringbuffer stream.");
+ return rc;
+ }
+
// Memory buffer for the profile data.
unsigned char *buffer = (unsigned char *) malloc (total);
if (buffer == NULL) {
ERROR (abstract->context, "Failed to allocate memory.");
+ dc_rbstream_free (rbstream);
return DC_STATUS_NOMEMORY;
}
- unsigned int available = 0;
unsigned int offset = total;
- // Align the ringbuffer to packet boundaries. This results in a
- // virtual ringbuffer that is slightly larger than the actual
- // ringbuffer. Data outside the real ringbuffer is downloaded
- // and then immediately dropped.
- unsigned int rb_profile_begin = ifloor(layout->rb_profile_begin, SZ_PACKET);
- unsigned int rb_profile_end = iceil(layout->rb_profile_end, SZ_PACKET);
-
- // Align the initial memory address to the next packet boundary, and
- // calculate the amount of padding bytes, so we can easily skip
- // them later.
- unsigned int address = iceil(eop, SZ_PACKET);
- unsigned int skip = address - eop;
-
idx = last;
previous = eop;
for (unsigned int i = 0; i < count; ++i) {
@@ -534,6 +512,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
unsigned int current = array_uint_le (logbook + idx * layout->rb_logbook_size, layout->rb_logbook_size) * SZ_PAGE + layout->rb_profile_begin;
if (current < layout->rb_profile_begin || current >= layout->rb_profile_end) {
ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%04x).", current);
+ dc_rbstream_free (rbstream);
free(buffer);
return DC_STATUS_DATAFORMAT;
}
@@ -541,51 +520,19 @@ 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 nbytes = available;
- while (nbytes < length) {
- if (address == rb_profile_begin)
- address = rb_profile_end;
- address -= SZ_PACKET;
+ // Move to the begin of the current dive.
+ offset -= length;
- // Read the memory page.
- unsigned char packet[SZ_PACKET];
- rc = cressi_edy_device_read (abstract, address, packet, sizeof(packet));
- if (rc != DC_STATUS_SUCCESS) {
- ERROR (abstract->context, "Failed to read the memory page.");
- free(buffer);
- return rc;
- }
-
- // At the head and tail of the ringbuffer, the packet can
- // contain extra data, originating from the larger virtual
- // ringbuffer. This data must be removed from the packet.
- unsigned int head = 0;
- unsigned int tail = 0;
- unsigned int len = SZ_PACKET;
- if (address < layout->rb_profile_begin) {
- head = layout->rb_profile_begin - address;
- }
- if (address + SZ_PACKET > layout->rb_profile_end) {
- tail = (address + SZ_PACKET) - layout->rb_profile_end;
- }
- len -= head + tail;
- offset -= len;
-
- // Copy the data packet to the buffer.
- memcpy(buffer + offset, packet + head, len);
-
- // Update and emit a progress event.
- progress.current += len;
- device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
-
- nbytes += len - skip;
- skip = 0;
+ // Read the dive.
+ rc = dc_rbstream_read (rbstream, &progress, buffer + offset, length);
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to read the dive.");
+ dc_rbstream_free (rbstream);
+ free (buffer);
+ return rc;
}
- available = nbytes - length;
- previous = current;
-
- unsigned char *p = buffer + offset + available;
+ unsigned char *p = buffer + offset;
if (memcmp (p, device->fingerprint, sizeof (device->fingerprint)) == 0)
break;
@@ -593,11 +540,14 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
if (callback && !callback (p, length, p, sizeof (device->fingerprint), userdata))
break;
+ previous = current;
+
if (idx == layout->rb_logbook_begin)
idx = layout->rb_logbook_end;
idx--;
}
+ dc_rbstream_free (rbstream);
free(buffer);
return DC_STATUS_SUCCESS;
diff --git a/src/cressi_leonardo.c b/src/cressi_leonardo.c
index 7e1df90..5259fe5 100644
--- a/src/cressi_leonardo.c
+++ b/src/cressi_leonardo.c
@@ -498,7 +498,7 @@ cressi_leonardo_extract_dives (dc_device_t *abstract, const unsigned char data[]
}
if (previous && previous != footer + 2) {
- ERROR (abstract->context, "Profiles are not continuous (0x%04x 0x%04x 0x%04x).", header, footer, previous);
+ ERROR (context, "Profiles are not continuous (0x%04x 0x%04x 0x%04x).", header, footer, previous);
free (buffer);
return DC_STATUS_DATAFORMAT;
}
diff --git a/src/diverite_nitekq.c b/src/diverite_nitekq.c
index 30060cd..1565779 100644
--- a/src/diverite_nitekq.c
+++ b/src/diverite_nitekq.c
@@ -217,7 +217,10 @@ diverite_nitekq_device_close (dc_device_t *abstract)
dc_status_t rc = DC_STATUS_SUCCESS;
// Disconnect.
- diverite_nitekq_send (device, DISCONNECT);
+ rc = diverite_nitekq_send (device, DISCONNECT);
+ if (rc != DC_STATUS_SUCCESS) {
+ dc_status_set_error(&status, rc);
+ }
// Close the device.
rc = dc_serial_close (device->port);
diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c
index 0b7a94d..55ce9d6 100644
--- a/src/hw_ostc_parser.c
+++ b/src/hw_ostc_parser.c
@@ -307,7 +307,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser)
return DC_STATUS_SUCCESS;
}
-dc_status_t
+static dc_status_t
hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int hwos, unsigned int model)
{
hw_ostc_parser_t *parser = NULL;
diff --git a/src/irda.c b/src/irda.c
index 00b749c..2271a69 100644
--- a/src/irda.c
+++ b/src/irda.c
@@ -36,6 +36,7 @@
#include // irda
#include // select
#include // ioctl
+ #include
#endif
#include "irda.h"
@@ -47,6 +48,7 @@
typedef int s_ssize_t;
typedef DWORD s_errcode_t;
#define S_ERRNO WSAGetLastError ()
+#define S_EINTR WSAEINTR
#define S_EAGAIN WSAEWOULDBLOCK
#define S_ENOMEM WSA_NOT_ENOUGH_MEMORY
#define S_EINVAL WSAEINVAL
@@ -59,6 +61,7 @@ typedef DWORD s_errcode_t;
typedef ssize_t s_ssize_t;
typedef int s_errcode_t;
#define S_ERRNO errno
+#define S_EINTR EINTR
#define S_EAGAIN EAGAIN
#define S_ENOMEM ENOMEM
#define S_EINVAL EINVAL
@@ -405,23 +408,27 @@ dc_irda_read (dc_irda_t *device, void *data, size_t size, size_t *actual)
if (device == NULL) {
status = DC_STATUS_INVALIDARGS;
- goto out;
+ goto out_invalidargs;
}
- struct timeval tv;
- if (device->timeout >= 0) {
- tv.tv_sec = (device->timeout / 1000);
- tv.tv_usec = (device->timeout % 1000) * 1000;
- }
-
- fd_set fds;
- FD_ZERO (&fds);
- FD_SET (device->fd, &fds);
-
while (nbytes < size) {
- int rc = select (device->fd + 1, &fds, NULL, NULL, (device->timeout >= 0 ? &tv : NULL));
+ fd_set fds;
+ FD_ZERO (&fds);
+ FD_SET (device->fd, &fds);
+
+ struct timeval tvt;
+ if (device->timeout > 0) {
+ tvt.tv_sec = (device->timeout / 1000);
+ tvt.tv_usec = (device->timeout % 1000) * 1000;
+ } else if (device->timeout == 0) {
+ timerclear (&tvt);
+ }
+
+ int rc = select (device->fd + 1, &fds, NULL, NULL, device->timeout >= 0 ? &tvt : NULL);
if (rc < 0) {
s_errcode_t errcode = S_ERRNO;
+ if (errcode == S_EINTR)
+ continue; // Retry.
SYSERROR (device->context, errcode);
status = syserror(errcode);
goto out;
@@ -432,6 +439,8 @@ dc_irda_read (dc_irda_t *device, void *data, size_t size, size_t *actual)
s_ssize_t n = recv (device->fd, (char*) data + nbytes, size - nbytes, 0);
if (n < 0) {
s_errcode_t errcode = S_ERRNO;
+ if (errcode == S_EINTR || errcode == S_EAGAIN)
+ continue; // Retry.
SYSERROR (device->context, errcode);
status = syserror(errcode);
goto out;
@@ -449,6 +458,7 @@ dc_irda_read (dc_irda_t *device, void *data, size_t size, size_t *actual)
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes);
+out_invalidargs:
if (actual)
*actual = nbytes;
@@ -463,16 +473,36 @@ dc_irda_write (dc_irda_t *device, const void *data, size_t size, size_t *actual)
if (device == NULL) {
status = DC_STATUS_INVALIDARGS;
- goto out;
+ goto out_invalidargs;
}
while (nbytes < size) {
- s_ssize_t n = send (device->fd, (char*) data + nbytes, size - nbytes, 0);
- if (n < 0) {
+ fd_set fds;
+ FD_ZERO (&fds);
+ FD_SET (device->fd, &fds);
+
+ int rc = select (device->fd + 1, NULL, &fds, NULL, NULL);
+ if (rc < 0) {
s_errcode_t errcode = S_ERRNO;
+ if (errcode == S_EINTR)
+ continue; // Retry.
SYSERROR (device->context, errcode);
status = syserror(errcode);
goto out;
+ } else if (rc == 0) {
+ break; // Timeout.
+ }
+
+ s_ssize_t n = send (device->fd, (char*) data + nbytes, size - nbytes, 0);
+ if (n < 0) {
+ s_errcode_t errcode = S_ERRNO;
+ if (errcode == S_EINTR || errcode == S_EAGAIN)
+ continue; // Retry.
+ SYSERROR (device->context, errcode);
+ status = syserror(errcode);
+ goto out;
+ } else if (n == 0) {
+ break; // EOF.
}
nbytes += n;
@@ -485,6 +515,7 @@ dc_irda_write (dc_irda_t *device, const void *data, size_t size, size_t *actual)
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes);
+out_invalidargs:
if (actual)
*actual = nbytes;
diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols
index 046e55c..a3e752f 100644
--- a/src/libdivecomputer.symbols
+++ b/src/libdivecomputer.symbols
@@ -98,7 +98,6 @@ mares_puck_extract_dives
mares_darwin_device_open
mares_darwin_extract_dives
mares_iconhd_device_open
-mares_iconhd_extract_dives
oceanic_atom2_device_open
oceanic_atom2_device_open2
oceanic_atom2_device_version
diff --git a/src/mares_darwin_parser.c b/src/mares_darwin_parser.c
index ac2c16f..73963e5 100644
--- a/src/mares_darwin_parser.c
+++ b/src/mares_darwin_parser.c
@@ -272,12 +272,13 @@ mares_darwin_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
// Deco stop
if (deco) {
- sample.event.type = SAMPLE_EVENT_DECOSTOP;
- sample.event.time = 0;
- sample.event.flags = 0;
- sample.event.value = 0;
- if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
+ sample.deco.type = DC_DECO_DECOSTOP;
+ } else {
+ sample.deco.type = DC_DECO_NDL;
}
+ sample.deco.time = 0;
+ sample.deco.depth = 0.0;
+ if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
if (parser->samplesize == 3) {
unsigned int type = (time / 20 + 2) % 3;
diff --git a/src/mares_iconhd.c b/src/mares_iconhd.c
index 9c33307..28e7717 100644
--- a/src/mares_iconhd.c
+++ b/src/mares_iconhd.c
@@ -29,6 +29,7 @@
#include "device-private.h"
#include "serial.h"
#include "array.h"
+#include "rbstream.h"
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
@@ -414,51 +415,46 @@ mares_iconhd_device_dump (dc_device_t *abstract, dc_buffer_t *buffer)
static dc_status_t
mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata)
{
+ dc_status_t rc = DC_STATUS_SUCCESS;
mares_iconhd_device_t *device = (mares_iconhd_device_t *) abstract;
- dc_buffer_t *buffer = dc_buffer_new (device->layout->memsize);
- if (buffer == NULL)
- return DC_STATUS_NOMEMORY;
-
- dc_status_t rc = mares_iconhd_device_dump (abstract, buffer);
- if (rc != DC_STATUS_SUCCESS) {
- dc_buffer_free (buffer);
- return rc;
- }
-
- // Emit a device info event.
- unsigned char *data = dc_buffer_get_data (buffer);
- dc_event_devinfo_t devinfo;
- devinfo.model = device->model;
- devinfo.firmware = 0;
- devinfo.serial = array_uint32_le (data + 0x0C);
- device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
-
- rc = mares_iconhd_extract_dives (abstract, dc_buffer_get_data (buffer),
- dc_buffer_get_size (buffer), callback, userdata);
-
- dc_buffer_free (buffer);
-
- return rc;
-}
-
-
-dc_status_t
-mares_iconhd_extract_dives (dc_device_t *abstract, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata)
-{
- mares_iconhd_device_t *device = (mares_iconhd_device_t *) abstract;
- dc_context_t *context = (abstract ? abstract->context : NULL);
-
if (!ISINSTANCE (abstract))
return DC_STATUS_INVALIDARGS;
const mares_iconhd_layout_t *layout = device->layout;
- if (size < layout->memsize)
- return DC_STATUS_DATAFORMAT;
+ // Enable progress notifications.
+ dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER;
+ progress.maximum = layout->rb_profile_end - layout->rb_profile_begin + 4;
+ 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 serial number.
+ unsigned char serial[4] = {0};
+ rc = mares_iconhd_device_read (abstract, 0x0C, serial, sizeof (serial));
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to read the memory.");
+ return rc;
+ }
+
+ // Update and emit a progress event.
+ progress.current += sizeof (serial);
+ device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
+
+ // Emit a device info event.
+ dc_event_devinfo_t devinfo;
+ devinfo.model = device->model;
+ devinfo.firmware = 0;
+ devinfo.serial = array_uint32_le (serial);
+ device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
// Get the model code.
- unsigned int model = device ? device->model : data[0];
+ unsigned int model = device->model;
// Get the corresponding dive header size.
unsigned int header = 0x5C;
@@ -473,29 +469,57 @@ mares_iconhd_extract_dives (dc_device_t *abstract, const unsigned char data[], u
unsigned int eop = 0;
const unsigned int config[] = {0x2001, 0x3001};
for (unsigned int i = 0; i < sizeof (config) / sizeof (*config); ++i) {
- eop = array_uint32_le (data + config[i]);
+ // Read the pointer.
+ unsigned char pointer[4] = {0};
+ rc = mares_iconhd_device_read (abstract, config[i], pointer, sizeof (pointer));
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to read the memory.");
+ return rc;
+ }
+
+ // Update and emit a progress event.
+ progress.maximum += sizeof (pointer);
+ progress.current += sizeof (pointer);
+ device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
+
+ eop = array_uint32_le (pointer);
if (eop != 0xFFFFFFFF)
break;
}
if (eop < layout->rb_profile_begin || eop >= layout->rb_profile_end) {
if (eop == 0xFFFFFFFF)
return DC_STATUS_SUCCESS; // No dives available.
- ERROR (context, "Ringbuffer pointer out of range (0x%08x).", eop);
+ ERROR (abstract->context, "Ringbuffer pointer out of range (0x%08x).", eop);
return DC_STATUS_DATAFORMAT;
}
- // Make the ringbuffer linear, to avoid having to deal with the wrap point.
+ // 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);
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to create the ringbuffer stream.");
+ return rc;
+ }
+
+ // Allocate memory for the dives.
unsigned char *buffer = (unsigned char *) malloc (layout->rb_profile_end - layout->rb_profile_begin);
if (buffer == NULL) {
- ERROR (context, "Failed to allocate memory.");
+ ERROR (abstract->context, "Failed to allocate memory.");
+ dc_rbstream_free (rbstream);
return DC_STATUS_NOMEMORY;
}
- memcpy (buffer + 0, data + eop, layout->rb_profile_end - eop);
- memcpy (buffer + layout->rb_profile_end - eop, data + layout->rb_profile_begin, eop - layout->rb_profile_begin);
-
unsigned int offset = layout->rb_profile_end - layout->rb_profile_begin;
while (offset >= header + 4) {
+ // Read the first part of the dive header.
+ rc = dc_rbstream_read (rbstream, &progress, buffer + offset - header, header);
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to read the dive.");
+ dc_rbstream_free (rbstream);
+ free (buffer);
+ return rc;
+ }
+
// Get the number of samples in the profile data.
unsigned int type = 0, nsamples = 0;
if (model == SMART || model == SMARTAPNEA) {
@@ -533,6 +557,17 @@ mares_iconhd_extract_dives (dc_device_t *abstract, const unsigned char data[], u
samplesize = 14;
fingerprint = 0x40;
}
+ if (offset < headersize)
+ break;
+
+ // Read the second part of the dive header.
+ rc = dc_rbstream_read (rbstream, &progress, buffer + offset - headersize, headersize - header);
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to read the dive.");
+ dc_rbstream_free (rbstream);
+ free (buffer);
+ return rc;
+ }
// Calculate the total number of bytes for this dive.
// If the buffer does not contain that much bytes, we reached the
@@ -542,9 +577,6 @@ mares_iconhd_extract_dives (dc_device_t *abstract, const unsigned char data[], u
if (model == ICONHDNET) {
nbytes += (nsamples / 4) * 8;
} else if (model == SMARTAPNEA) {
- if (offset < headersize)
- break;
-
unsigned int settings = array_uint16_le (buffer + offset - headersize + 0x1C);
unsigned int divetime = array_uint32_le (buffer + offset - headersize + 0x24);
unsigned int samplerate = 1 << ((settings >> 9) & 0x03);
@@ -554,6 +586,15 @@ mares_iconhd_extract_dives (dc_device_t *abstract, const unsigned char data[], u
if (offset < nbytes)
break;
+ // Read the remainder of the dive.
+ rc = dc_rbstream_read (rbstream, &progress, buffer + offset - nbytes, nbytes - headersize);
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to read the dive.");
+ dc_rbstream_free (rbstream);
+ free (buffer);
+ return rc;
+ }
+
// Move to the start of the dive.
offset -= nbytes;
@@ -566,17 +607,16 @@ mares_iconhd_extract_dives (dc_device_t *abstract, const unsigned char data[], u
unsigned char *fp = buffer + offset + length - headersize + fingerprint;
if (device && memcmp (fp, device->fingerprint, sizeof (device->fingerprint)) == 0) {
- free (buffer);
- return DC_STATUS_SUCCESS;
+ break;
}
if (callback && !callback (buffer + offset, length, fp, sizeof (device->fingerprint), userdata)) {
- free (buffer);
- return DC_STATUS_SUCCESS;
+ break;
}
}
+ dc_rbstream_free (rbstream);
free (buffer);
- return DC_STATUS_SUCCESS;
+ return rc;
}
diff --git a/src/mares_iconhd_parser.c b/src/mares_iconhd_parser.c
index 534d2ca..8e356be 100644
--- a/src/mares_iconhd_parser.c
+++ b/src/mares_iconhd_parser.c
@@ -603,15 +603,13 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t
// Some extra data.
if (parser->model == ICONHDNET && (nsamples % 4) == 0) {
// Pressure (1/100 bar).
- if (parser->ntanks > 0) {
- unsigned int pressure = array_uint16_le(data + offset);
- if (gasmix >= parser->ntanks) {
- ERROR (abstract->context, "Invalid tank index.");
- return DC_STATUS_DATAFORMAT;
- }
+ unsigned int pressure = array_uint16_le(data + offset);
+ if (gasmix < parser->ntanks) {
sample.pressure.tank = gasmix;
sample.pressure.value = pressure / 100.0;
if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata);
+ } else if (pressure != 0) {
+ WARNING (abstract->context, "Invalid tank with non-zero pressure.");
}
offset += 8;
diff --git a/src/mares_nemo_parser.c b/src/mares_nemo_parser.c
index 29b51b1..7b24ca4 100644
--- a/src/mares_nemo_parser.c
+++ b/src/mares_nemo_parser.c
@@ -412,12 +412,13 @@ mares_nemo_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t c
// Deco stop
if (deco) {
- sample.event.type = SAMPLE_EVENT_DECOSTOP;
- sample.event.time = 0;
- sample.event.flags = 0;
- sample.event.value = 0;
- if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
+ sample.deco.type = DC_DECO_DECOSTOP;
+ } else {
+ sample.deco.type = DC_DECO_NDL;
}
+ sample.deco.time = 0;
+ sample.deco.depth = 0.0;
+ if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
// Pressure (1 bar).
if (parser->sample_size == 3) {
diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c
index 01e4fd4..34cc592 100644
--- a/src/oceanic_atom2.c
+++ b/src/oceanic_atom2.c
@@ -714,7 +714,10 @@ oceanic_atom2_device_close (dc_device_t *abstract)
dc_status_t rc = DC_STATUS_SUCCESS;
// Send the quit command.
- oceanic_atom2_quit (device);
+ rc = oceanic_atom2_quit (device);
+ if (rc != DC_STATUS_SUCCESS) {
+ dc_status_set_error(&status, rc);
+ }
// Close the device.
rc = dc_serial_close (device->port);
diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c
index 08847da..79060ab 100644
--- a/src/oceanic_atom2_parser.c
+++ b/src/oceanic_atom2_parser.c
@@ -442,6 +442,9 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
} else if (parser->model == I450T) {
o2_offset = 0x30;
ngasmixes = 3;
+ } else if (parser->model == ZEN) {
+ o2_offset = header + 4;
+ ngasmixes = 2;
} else {
o2_offset = header + 4;
ngasmixes = 3;
diff --git a/src/oceanic_common.c b/src/oceanic_common.c
index a463038..427b326 100644
--- a/src/oceanic_common.c
+++ b/src/oceanic_common.c
@@ -27,6 +27,7 @@
#include "context-private.h"
#include "device-private.h"
#include "ringbuffer.h"
+#include "rbstream.h"
#include "array.h"
#define VTABLE(abstract) ((oceanic_common_device_vtable_t *) abstract->vtable)
@@ -39,22 +40,6 @@
#define INVALID 0
-static unsigned int
-ifloor (unsigned int x, unsigned int n)
-{
- // Round down to next lower multiple.
- return (x / n) * n;
-}
-
-
-static unsigned int
-iceil (unsigned int x, unsigned int n)
-{
- // Round up to next higher multiple.
- return ((x + n - 1) / n) * n;
-}
-
-
static unsigned int
get_profile_first (const unsigned char data[], const oceanic_common_layout_t *layout)
{
@@ -234,177 +219,94 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr
return DC_STATUS_DATAFORMAT;
}
- // Convert the first/last pointers to begin/end/count pointers.
- unsigned int rb_logbook_entry_begin, rb_logbook_entry_end,
- rb_logbook_entry_size;
+ // Calculate the end pointer and the number of bytes.
+ unsigned int rb_logbook_end, rb_logbook_size;
if (layout->pt_mode_global == 0) {
- rb_logbook_entry_begin = rb_logbook_first;
- rb_logbook_entry_end = RB_LOGBOOK_INCR (rb_logbook_last, layout->rb_logbook_entry_size, layout);
- rb_logbook_entry_size = RB_LOGBOOK_DISTANCE (rb_logbook_first, rb_logbook_last, layout) + layout->rb_logbook_entry_size;
+ rb_logbook_end = RB_LOGBOOK_INCR (rb_logbook_last, layout->rb_logbook_entry_size, layout);
+ rb_logbook_size = RB_LOGBOOK_DISTANCE (rb_logbook_first, rb_logbook_last, layout) + layout->rb_logbook_entry_size;
} else {
- rb_logbook_entry_begin = rb_logbook_first;
- rb_logbook_entry_end = rb_logbook_last;
- rb_logbook_entry_size = RB_LOGBOOK_DISTANCE (rb_logbook_first, rb_logbook_last, layout);
+ rb_logbook_end = rb_logbook_last;
+ rb_logbook_size = RB_LOGBOOK_DISTANCE (rb_logbook_first, rb_logbook_last, layout);
// In a typical ringbuffer implementation with only two begin/end
// pointers, there is no distinction possible between an empty and
// a 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.
if (rb_logbook_first == rb_logbook_last)
- rb_logbook_entry_size = layout->rb_logbook_end - layout->rb_logbook_begin;
+ rb_logbook_size = layout->rb_logbook_end - layout->rb_logbook_begin;
}
- // Check whether the ringbuffer is full.
- int full = (rb_logbook_entry_size == (layout->rb_logbook_end - layout->rb_logbook_begin));
-
- // Align the pointers to page boundaries.
- unsigned int rb_logbook_page_begin, rb_logbook_page_end,
- rb_logbook_page_size;
- if (full) {
- // Full ringbuffer.
- rb_logbook_page_begin = iceil (rb_logbook_entry_end, PAGESIZE);
- rb_logbook_page_end = rb_logbook_page_begin;
- rb_logbook_page_size = rb_logbook_entry_size;
- } else {
- // Non-full ringbuffer.
- rb_logbook_page_begin = ifloor (rb_logbook_entry_begin, PAGESIZE);
- rb_logbook_page_end = iceil (rb_logbook_entry_end, PAGESIZE);
- rb_logbook_page_size = rb_logbook_entry_size +
- (rb_logbook_entry_begin - rb_logbook_page_begin) +
- (rb_logbook_page_end - rb_logbook_entry_end);
- }
-
- // Check whether the last entry is not aligned to a page boundary.
- int unaligned = (rb_logbook_entry_end != rb_logbook_page_end);
-
// Update and emit a progress event.
progress->current += PAGESIZE;
progress->maximum += PAGESIZE;
- progress->maximum -= (layout->rb_logbook_end - layout->rb_logbook_begin) - rb_logbook_page_size;
+ progress->maximum -= (layout->rb_logbook_end - layout->rb_logbook_begin) - rb_logbook_size;
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
// Exit if there are no dives.
- if (rb_logbook_page_size == 0) {
+ if (rb_logbook_size == 0) {
return DC_STATUS_SUCCESS;
}
// Allocate memory for the logbook entries.
- if (!dc_buffer_resize (logbook, rb_logbook_page_size))
+ if (!dc_buffer_resize (logbook, rb_logbook_size))
return DC_STATUS_NOMEMORY;
// Cache the logbook pointer.
unsigned char *logbooks = dc_buffer_get_data (logbook);
- // Since entries are not necessary aligned on page boundaries,
- // the memory buffer may contain padding entries on both sides.
- // The memory area which contains the valid entries is marked
- // with a number of additional variables.
- unsigned int begin = 0;
- unsigned int end = rb_logbook_page_size;
- if (!full) {
- begin += rb_logbook_entry_begin - rb_logbook_page_begin;
- end -= rb_logbook_page_end - rb_logbook_entry_end;
+ // 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);
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to create the ringbuffer stream.");
+ return rc;
}
// The logbook ringbuffer is read backwards to retrieve the most recent
// entries first. If an already downloaded entry is identified (by means
// of its fingerprint), the transfer is aborted immediately to reduce
- // the transfer time. When necessary, padding entries are downloaded
- // (but not processed) to align all read requests on page boundaries.
+ // the transfer time.
unsigned int nbytes = 0;
- unsigned int current = end;
- unsigned int offset = rb_logbook_page_size;
- unsigned int address = rb_logbook_page_end;
- while (nbytes < rb_logbook_page_size) {
- // Handle the ringbuffer wrap point.
- if (address == layout->rb_logbook_begin)
- address = layout->rb_logbook_end;
+ unsigned int offset = rb_logbook_size;
+ while (nbytes < rb_logbook_size) {
+ // Move to the start of the current entry.
+ offset -= layout->rb_logbook_entry_size;
- // Calculate the optimal packet size.
- unsigned int len = PAGESIZE * device->multipage;
- if (layout->rb_logbook_begin + len > address)
- len = address - layout->rb_logbook_begin; // End of ringbuffer.
- if (nbytes + len > rb_logbook_page_size)
- len = rb_logbook_page_size - nbytes; // End of logbooks.
-
- // Move to the start of the current page.
- address -= len;
- offset -= len;
-
- // Read the logbook page.
- rc = dc_device_read (abstract, address, logbooks + offset, len);
+ // Read the logbook entry.
+ rc = dc_rbstream_read (rbstream, progress, logbooks + offset, layout->rb_logbook_entry_size);
if (rc != DC_STATUS_SUCCESS) {
- ERROR (abstract->context, "Failed to read the memory page.");
+ ERROR (abstract->context, "Failed to read the memory.");
+ dc_rbstream_free (rbstream);
return rc;
}
- // Update and emit a progress event.
- progress->current += len;
- device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
+ nbytes += layout->rb_logbook_entry_size;
- // A full ringbuffer needs some special treatment to avoid
- // having to download the first/last page twice. When a full
- // ringbuffer is not aligned to page boundaries, this page
- // will contain both the most recent and oldest entry.
- if (full && unaligned) {
- if (nbytes == 0) {
- // After downloading the first page, move both the oldest
- // and most recent entries to their correct location.
- unsigned int oldest = rb_logbook_page_end - rb_logbook_entry_end;
- unsigned int newest = len - oldest;
- // Move the oldest entries down to the start of the buffer.
- memcpy (logbooks, logbooks + offset + newest, oldest);
- // Move the newest entries up to the end of the buffer.
- memmove (logbooks + offset + oldest, logbooks + offset, newest);
- // Adjust the current page offset to the new position.
- offset += oldest;
- } else if (nbytes + len == rb_logbook_page_size) {
- // After downloading the last page, pretend we have also
- // downloaded those oldest entries from the first page.
- offset = 0;
- }
- }
-
- nbytes += len;
-
- // Process the logbook entries.
- int abort = 0;
- while (current >= offset + layout->rb_logbook_entry_size &&
- current != offset && current != begin)
- {
- // Move to the start of the current entry.
- current -= layout->rb_logbook_entry_size;
-
- // Check for uninitialized entries. Normally, such entries are
- // never present, except when the ringbuffer is actually empty,
- // but the ringbuffer pointers are not set to their empty values.
- // This appears to happen on some devices, and we attempt to
- // fix this here.
- if (array_isequal (logbooks + current, layout->rb_logbook_entry_size, 0xFF)) {
- WARNING (abstract->context, "Uninitialized logbook entries detected!");
- begin = current + layout->rb_logbook_entry_size;
- abort = 1;
- break;
- }
-
- // Compare the fingerprint to identify previously downloaded entries.
- if (memcmp (logbooks + current, device->fingerprint, layout->rb_logbook_entry_size) == 0) {
- begin = current + layout->rb_logbook_entry_size;
- abort = 1;
- break;
- }
- }
-
- // Stop reading pages too.
- if (abort)
+ // Check for uninitialized entries. Normally, such entries are
+ // never present, except when the ringbuffer is actually empty,
+ // but the ringbuffer pointers are not set to their empty values.
+ // This appears to happen on some devices, and we attempt to
+ // fix this here.
+ if (array_isequal (logbooks + offset, layout->rb_logbook_entry_size, 0xFF)) {
+ WARNING (abstract->context, "Uninitialized logbook entries detected!");
+ offset += layout->rb_logbook_entry_size;
break;
+ }
+
+ // Compare the fingerprint to identify previously downloaded entries.
+ if (memcmp (logbooks + offset, device->fingerprint, layout->rb_logbook_entry_size) == 0) {
+ offset += layout->rb_logbook_entry_size;
+ break;
+ }
}
// Update and emit a progress event.
- progress->maximum -= rb_logbook_page_size - nbytes;
+ progress->maximum -= rb_logbook_size - nbytes;
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
- dc_buffer_slice (logbook, begin, end - begin);
+ dc_buffer_slice (logbook, offset, rb_logbook_size - offset);
+
+ dc_rbstream_free (rbstream);
return DC_STATUS_SUCCESS;
}
@@ -492,20 +394,24 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
progress->maximum -= (layout->rb_profile_end - layout->rb_profile_begin) - rb_profile_size;
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
+ // 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);
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to create the ringbuffer stream.");
+ return rc;
+ }
+
// Memory buffer for the profile data.
unsigned char *profiles = (unsigned char *) malloc (rb_profile_size + rb_logbook_size);
if (profiles == NULL) {
+ ERROR (abstract->context, "Failed to allocate memory.");
+ dc_rbstream_free (rbstream);
return DC_STATUS_NOMEMORY;
}
// Keep track of the current position.
unsigned int offset = rb_profile_size + rb_logbook_size;
- unsigned int address = rb_profile_end;
-
- // When using multipage reads, the last packet can contain data from more
- // than one dive. Therefore, the remaining data of this package (and its
- // size) needs to be preserved for the next dive.
- unsigned int available = 0;
// Traverse the logbook ringbuffer backwards to retrieve the most recent
// dives first. The logbook ringbuffer is linearized at this point, so
@@ -528,6 +434,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
{
ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).",
rb_entry_first, rb_entry_last);
+ dc_rbstream_free (rbstream);
free (profiles);
return DC_STATUS_DATAFORMAT;
}
@@ -549,56 +456,33 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
break;
}
- // Read the profile data.
- unsigned int nbytes = available;
- while (nbytes < rb_entry_size + gap) {
- // Handle the ringbuffer wrap point.
- if (address == layout->rb_profile_begin)
- address = layout->rb_profile_end;
+ // Move to the start of the current dive.
+ offset -= rb_entry_size + gap;
- // Calculate the optimal packet size.
- unsigned int len = PAGESIZE * device->multipage;
- if (layout->rb_profile_begin + len > address)
- len = address - layout->rb_profile_begin; // End of ringbuffer.
- if (nbytes + len > remaining)
- len = remaining - nbytes; // End of profile.
-
- // Move to the start of the current page.
- address -= len;
- offset -= len;
-
- // Read the profile page.
- rc = dc_device_read (abstract, address, profiles + offset, len);
- if (rc != DC_STATUS_SUCCESS) {
- free (profiles);
- return rc;
- }
-
- // Update and emit a progress event.
- progress->current += len;
- device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
-
- nbytes += len;
+ // Read the dive.
+ rc = dc_rbstream_read (rbstream, progress, profiles + offset, rb_entry_size + gap);
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to read the dive.");
+ dc_rbstream_free (rbstream);
+ free (profiles);
+ return rc;
}
- available = nbytes - (rb_entry_size + gap);
remaining -= rb_entry_size + gap;
previous = rb_entry_first;
// Prepend the logbook entry to the profile data. The memory buffer is
- // large enough to store this entry, but any data that belongs to the
- // next dive needs to be moved down first.
- if (available)
- memmove (profiles + offset - layout->rb_logbook_entry_size, profiles + offset, available);
+ // large enough to store this entry.
offset -= layout->rb_logbook_entry_size;
- memcpy (profiles + offset + available, logbooks + entry, layout->rb_logbook_entry_size);
+ memcpy (profiles + offset, logbooks + entry, layout->rb_logbook_entry_size);
- unsigned char *p = profiles + offset + available;
+ unsigned char *p = profiles + offset;
if (callback && !callback (p, rb_entry_size + layout->rb_logbook_entry_size, p, layout->rb_logbook_entry_size, userdata)) {
break;
}
}
+ dc_rbstream_free (rbstream);
free (profiles);
return DC_STATUS_SUCCESS;
diff --git a/src/oceanic_veo250.c b/src/oceanic_veo250.c
index 9db215c..033081d 100644
--- a/src/oceanic_veo250.c
+++ b/src/oceanic_veo250.c
@@ -337,7 +337,10 @@ oceanic_veo250_device_close (dc_device_t *abstract)
dc_status_t rc = DC_STATUS_SUCCESS;
// Switch the device back to surface mode.
- oceanic_veo250_quit (device);
+ rc = oceanic_veo250_quit (device);
+ if (rc != DC_STATUS_SUCCESS) {
+ dc_status_set_error(&status, rc);
+ }
// Close the device.
rc = dc_serial_close (device->port);
diff --git a/src/oceanic_vtpro.c b/src/oceanic_vtpro.c
index 22d042b..3128079 100644
--- a/src/oceanic_vtpro.c
+++ b/src/oceanic_vtpro.c
@@ -517,7 +517,10 @@ oceanic_vtpro_device_close (dc_device_t *abstract)
dc_status_t rc = DC_STATUS_SUCCESS;
// Switch the device back to surface mode.
- oceanic_vtpro_quit (device);
+ rc = oceanic_vtpro_quit (device);
+ if (rc != DC_STATUS_SUCCESS) {
+ dc_status_set_error(&status, rc);
+ }
// Close the device.
rc = dc_serial_close (device->port);
diff --git a/src/oceanic_vtpro_parser.c b/src/oceanic_vtpro_parser.c
index 859025e..1f9d7aa 100644
--- a/src/oceanic_vtpro_parser.c
+++ b/src/oceanic_vtpro_parser.c
@@ -333,7 +333,7 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
// Time.
if (interval)
- time += interval;
+ time = timestamp * 60 + (i + 1) * interval;
else
time = timestamp * 60 + (i + 1) * 60.0 / count + 0.5;
sample.time = time;
diff --git a/src/rbstream.c b/src/rbstream.c
new file mode 100644
index 0000000..07188e0
--- /dev/null
+++ b/src/rbstream.c
@@ -0,0 +1,176 @@
+/*
+ * libdivecomputer
+ *
+ * Copyright (C) 2016 Jef Driesen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include
+#include
+
+#include "rbstream.h"
+#include "context-private.h"
+#include "device-private.h"
+
+struct dc_rbstream_t {
+ dc_device_t *device;
+ unsigned int pagesize;
+ unsigned int packetsize;
+ unsigned int begin;
+ unsigned int end;
+ unsigned int address;
+ unsigned int available;
+ unsigned int skip;
+ unsigned char cache[];
+};
+
+static unsigned int
+ifloor (unsigned int x, unsigned int n)
+{
+ // Round down to next lower multiple.
+ return (x / n) * n;
+}
+
+static unsigned int
+iceil (unsigned int x, unsigned int n)
+{
+ // Round up to next higher multiple.
+ return ((x + n - 1) / n) * 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_t *rbstream = NULL;
+
+ if (out == NULL || device == NULL)
+ return DC_STATUS_INVALIDARGS;
+
+ // Page and packet size should be non-zero.
+ if (pagesize == 0 || packetsize == 0) {
+ ERROR (device->context, "Zero length page or packet size!");
+ return DC_STATUS_INVALIDARGS;
+ }
+
+ // Packet size should be a multiple of the page size.
+ if (packetsize % pagesize != 0) {
+ ERROR (device->context, "Packet size not a multiple of the page size!");
+ return DC_STATUS_INVALIDARGS;
+ }
+
+ // Ringbuffer boundaries should be aligned to the page size.
+ if (begin % pagesize != 0 || end % pagesize != 0) {
+ ERROR (device->context, "Ringbuffer not aligned to the page size!");
+ return DC_STATUS_INVALIDARGS;
+ }
+
+ // Address should be inside the ringbuffer.
+ if (address < begin || address > end) {
+ ERROR (device->context, "Address outside the ringbuffer!");
+ return DC_STATUS_INVALIDARGS;
+ }
+
+ // Allocate memory.
+ rbstream = (dc_rbstream_t *) malloc (sizeof(*rbstream) + packetsize);
+ if (rbstream == NULL) {
+ ERROR (device->context, "Failed to allocate memory.");
+ return DC_STATUS_NOMEMORY;
+ }
+
+ rbstream->device = device;
+ rbstream->pagesize = pagesize;
+ rbstream->packetsize = packetsize;
+ rbstream->begin = begin;
+ rbstream->end = end;
+ rbstream->address = iceil(address, pagesize);
+ 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)
+{
+ 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) {
+ // Handle the ringbuffer wrap point.
+ if (address == rbstream->begin)
+ 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;
+
+ // Read the packet into the cache.
+ rc = dc_device_read (rbstream->device, address, rbstream->cache, rbstream->packetsize);
+ if (rc != DC_STATUS_SUCCESS)
+ return rc;
+
+ available = len - skip;
+ skip = 0;
+ }
+
+ unsigned int length = available;
+ if (nbytes + length > size)
+ length = size - nbytes;
+
+ offset -= length;
+ available -= length;
+
+ memcpy (data + offset, rbstream->cache + available, length);
+
+ // Update and emit a progress event.
+ if (progress) {
+ progress->current += length;
+ device_event_emit (rbstream->device, DC_EVENT_PROGRESS, progress);
+ }
+
+ nbytes += length;
+ }
+
+ rbstream->address = address;
+ rbstream->available = available;
+ rbstream->skip = skip;
+
+ return rc;
+}
+
+dc_status_t
+dc_rbstream_free (dc_rbstream_t *rbstream)
+{
+ free (rbstream);
+
+ return DC_STATUS_SUCCESS;
+}
diff --git a/src/rbstream.h b/src/rbstream.h
new file mode 100644
index 0000000..be1d8f6
--- /dev/null
+++ b/src/rbstream.h
@@ -0,0 +1,78 @@
+/*
+ * libdivecomputer
+ *
+ * Copyright (C) 2016 Jef Driesen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#ifndef DC_RBSTREAM_H
+#define DC_RBSTREAM_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Opaque object representing a ringbuffer stream.
+ */
+typedef struct dc_rbstream_t dc_rbstream_t;
+
+/**
+ * Create a new ringbuffer stream.
+ *
+ * @param[out] rbstream A location to store the ringbuffer stream.
+ * @param[in] device A valid device object.
+ * @param[in] pagesize The page size in bytes.
+ * @param[in] packetsize The packet size in bytes.
+ * @param[in] begin The ringbuffer begin address.
+ * @param[in] end The ringbuffer end address.
+ * @param[in] address The stream start address.
+ * @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);
+
+/**
+ * Read data from the ringbuffer stream.
+ *
+ * @param[in] rbstream A valid ringbuffer stream.
+ * @param[in] progress An (optional) progress event structure.
+ * @param[out] data The memory buffer to read the data into.
+ * @param[in] size The number of bytes to read.
+ * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
+ * on failure.
+ */
+dc_status_t
+dc_rbstream_read (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsigned char data[], unsigned int size);
+
+/**
+ * Destroy the ringbuffer stream.
+ *
+ * @param[in] rbstream A valid ringbuffer stream.
+ * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
+ * on failure.
+ */
+dc_status_t
+dc_rbstream_free (dc_rbstream_t *rbstream);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* DC_RBSTREAM_H */
diff --git a/src/reefnet_sensus.c b/src/reefnet_sensus.c
index 51e9a7f..09c5266 100644
--- a/src/reefnet_sensus.c
+++ b/src/reefnet_sensus.c
@@ -152,9 +152,12 @@ reefnet_sensus_device_close (dc_device_t *abstract)
// Safely close the connection if the last handshake was
// successful, but no data transfer was ever initiated.
- if (device->waiting)
- reefnet_sensus_cancel (device);
-
+ if (device->waiting) {
+ rc = reefnet_sensus_cancel (device);
+ if (rc != DC_STATUS_SUCCESS) {
+ dc_status_set_error(&status, rc);
+ }
+ }
// Close the device.
rc = dc_serial_close (device->port);
diff --git a/src/serial_posix.c b/src/serial_posix.c
index 8d6737b..1b4a4d6 100644
--- a/src/serial_posix.c
+++ b/src/serial_posix.c
@@ -582,7 +582,7 @@ dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual)
if (device == NULL) {
status = DC_STATUS_INVALIDARGS;
- goto out;
+ goto out_invalidargs;
}
RETURN_IF_CUSTOM_SERIAL(device->context,
@@ -667,6 +667,7 @@ dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual)
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes);
+out_invalidargs:
if (actual)
*actual = nbytes;
@@ -681,7 +682,7 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act
if (device == NULL) {
status = DC_STATUS_INVALIDARGS;
- goto out;
+ goto out_invalidargs;
}
RETURN_IF_CUSTOM_SERIAL(device->context,
@@ -782,6 +783,7 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes);
+out_invalidargs:
if (actual)
*actual = nbytes;
diff --git a/src/serial_win32.c b/src/serial_win32.c
index eb5b867..406d0a2 100644
--- a/src/serial_win32.c
+++ b/src/serial_win32.c
@@ -425,7 +425,7 @@ dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual)
if (device == NULL) {
status = DC_STATUS_INVALIDARGS;
- goto out;
+ goto out_invalidargs;
}
RETURN_IF_CUSTOM_SERIAL(device->context,
@@ -450,6 +450,7 @@ dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual)
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, dwRead);
+out_invalidargs:
if (actual)
*actual = dwRead;
@@ -465,7 +466,7 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act
if (device == NULL) {
status = DC_STATUS_INVALIDARGS;
- goto out;
+ goto out_invalidargs;
}
RETURN_IF_CUSTOM_SERIAL(device->context,
@@ -529,6 +530,7 @@ dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *act
out:
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, dwWritten);
+out_invalidargs:
if (actual)
*actual = dwWritten;
diff --git a/src/shearwater_petrel.c b/src/shearwater_petrel.c
index b791388..13e1496 100644
--- a/src/shearwater_petrel.c
+++ b/src/shearwater_petrel.c
@@ -115,14 +115,24 @@ error_free:
static dc_status_t
shearwater_petrel_device_close (dc_device_t *abstract)
{
+ dc_status_t status = DC_STATUS_SUCCESS;
shearwater_common_device_t *device = (shearwater_common_device_t *) abstract;
+ dc_status_t rc = DC_STATUS_SUCCESS;
// Shutdown the device.
unsigned char request[] = {0x2E, 0x90, 0x20, 0x00};
- shearwater_common_transfer (device, request, sizeof (request), NULL, 0, NULL);
+ rc = shearwater_common_transfer (device, request, sizeof (request), NULL, 0, NULL);
+ if (rc != DC_STATUS_SUCCESS) {
+ dc_status_set_error(&status, rc);
+ }
// Close the device.
- return shearwater_common_close (device);
+ rc = shearwater_common_close (device);
+ if (rc != DC_STATUS_SUCCESS) {
+ dc_status_set_error(&status, rc);
+ }
+
+ return status;
}
diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c
index eaca0ec..8d5b71d 100644
--- a/src/shearwater_predator_parser.c
+++ b/src/shearwater_predator_parser.c
@@ -111,7 +111,7 @@ shearwater_predator_find_gasmix (shearwater_predator_parser_t *parser, unsigned
}
-dc_status_t
+static dc_status_t
shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int petrel)
{
shearwater_predator_parser_t *parser = NULL;
diff --git a/src/suunto_common2.c b/src/suunto_common2.c
index 2abe386..80b2477 100644
--- a/src/suunto_common2.c
+++ b/src/suunto_common2.c
@@ -26,6 +26,7 @@
#include "context-private.h"
#include "suunto_common2.h"
#include "ringbuffer.h"
+#include "rbstream.h"
#include "checksum.h"
#include "array.h"
@@ -294,102 +295,59 @@ suunto_common2_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
return DC_STATUS_DATAFORMAT;
}
- // Memory buffer to store all the dives.
-
- unsigned char *data = (unsigned char *) malloc (layout->rb_profile_end - layout->rb_profile_begin + SZ_MINIMUM);
- if (data == NULL) {
- ERROR (abstract->context, "Failed to allocate memory.");
- return DC_STATUS_NOMEMORY;
- }
-
// Calculate the total amount of bytes.
-
unsigned int remaining = RB_PROFILE_DISTANCE (layout, begin, end, count != 0);
// Update and emit a progress event.
-
progress.maximum -= (layout->rb_profile_end - layout->rb_profile_begin) - remaining;
progress.current += sizeof (header);
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
- // To reduce the number of read operations, we always try to read
- // packages with the largest possible size. As a consequence, the
- // last package of a dive can contain data from more than one dive.
- // Therefore, the remaining data of this package (and its size)
- // needs to be preserved for the next dive.
+ // 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);
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to create the ringbuffer stream.");
+ return rc;
+ }
- unsigned int available = 0;
+ // Memory buffer to store all the dives.
+ unsigned char *data = (unsigned char *) malloc (layout->rb_profile_end - layout->rb_profile_begin);
+ if (data == NULL) {
+ ERROR (abstract->context, "Failed to allocate memory.");
+ dc_rbstream_free (rbstream);
+ return DC_STATUS_NOMEMORY;
+ }
// The ring buffer is traversed backwards to retrieve the most recent
// dives first. This allows us to download only the new dives.
-
unsigned int current = last;
unsigned int previous = end;
- unsigned int address = previous;
- unsigned int offset = remaining + SZ_MINIMUM;
- while (remaining) {
+ unsigned int offset = remaining;
+ while (offset) {
// Calculate the size of the current dive.
unsigned int size = RB_PROFILE_DISTANCE (layout, current, previous, 1);
- if (size < 4 || size > remaining) {
- ERROR (abstract->context, "Unexpected profile size (%u %u).", size, remaining);
+ if (size < 4 || size > offset) {
+ ERROR (abstract->context, "Unexpected profile size (%u %u).", size, offset);
+ dc_rbstream_free (rbstream);
free (data);
return DC_STATUS_DATAFORMAT;
}
- unsigned int nbytes = available;
- while (nbytes < size) {
- // Handle the ringbuffer wrap point.
- if (address == layout->rb_profile_begin)
- address = layout->rb_profile_end;
+ // Move to the begin of the current dive.
+ offset -= size;
- // Calculate the package size. Try with the largest possible
- // size first, and adjust when the end of the ringbuffer or
- // the end of the profile data is reached.
- unsigned int len = SZ_PACKET;
- if (layout->rb_profile_begin + len > address)
- len = address - layout->rb_profile_begin; // End of ringbuffer.
- if (nbytes + len > remaining)
- len = remaining - nbytes; // End of profile.
- /*if (nbytes + len > size)
- len = size - nbytes;*/ // End of dive (for testing only).
-
- // Move to the begin of the current package.
- offset -= len;
- address -= len;
-
- // Always read at least the minimum amount of bytes, because
- // reading fewer bytes is unreliable. The memory buffer is
- // large enough to prevent buffer overflows, and the extra
- // bytes are automatically ignored (due to reading backwards).
- unsigned int extra = 0;
- if (len < SZ_MINIMUM)
- extra = SZ_MINIMUM - len;
-
- // Read the package.
- rc = suunto_common2_device_read (abstract, address - extra, data + offset - extra, len + extra);
- if (rc != DC_STATUS_SUCCESS) {
- ERROR (abstract->context, "Failed to read the memory.");
- free (data);
- return rc;
- }
-
- // Update and emit a progress event.
- progress.current += len;
- device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
-
- // Next package.
- nbytes += len;
+ // Read the dive.
+ rc = dc_rbstream_read (rbstream, &progress, data + offset, size);
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to read the dive.");
+ dc_rbstream_free (rbstream);
+ free (data);
+ return rc;
}
- // The last package of the current dive contains the previous and
- // next pointers (in a continuous memory area). It can also contain
- // a number of bytes from the next dive.
-
- remaining -= size;
- available = nbytes - size;
-
- unsigned char *p = data + offset + available;
+ unsigned char *p = data + offset;
unsigned int prev = array_uint16_le (p + 0);
unsigned int next = array_uint16_le (p + 2);
if (prev < layout->rb_profile_begin ||
@@ -398,11 +356,13 @@ suunto_common2_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
next >= layout->rb_profile_end)
{
ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%04x 0x%04x).", prev, next);
+ dc_rbstream_free (rbstream);
free (data);
return DC_STATUS_DATAFORMAT;
}
if (next != previous && next != current) {
ERROR (abstract->context, "Profiles are not continuous (0x%04x 0x%04x 0x%04x).", current, next, previous);
+ dc_rbstream_free (rbstream);
free (data);
return DC_STATUS_DATAFORMAT;
}
@@ -410,11 +370,13 @@ suunto_common2_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
if (next != current) {
unsigned int fp_offset = layout->fingerprint + 4;
if (memcmp (p + fp_offset, device->fingerprint, sizeof (device->fingerprint)) == 0) {
+ dc_rbstream_free (rbstream);
free (data);
return DC_STATUS_SUCCESS;
}
if (callback && !callback (p + 4, size - 4, p + fp_offset, sizeof (device->fingerprint), userdata)) {
+ dc_rbstream_free (rbstream);
free (data);
return DC_STATUS_SUCCESS;
}
@@ -428,6 +390,7 @@ suunto_common2_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
current = prev;
}
+ dc_rbstream_free (rbstream);
free (data);
return status;
diff --git a/src/suunto_d9_parser.c b/src/suunto_d9_parser.c
index 39dbca0..88e4aac 100644
--- a/src/suunto_d9_parser.c
+++ b/src/suunto_d9_parser.c
@@ -594,28 +594,28 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca
seconds = data[offset + 1];
switch (type & 0x7F) {
case 0x00: // Voluntary Safety Stop
- sample.event.type = SAMPLE_EVENT_SAFETYSTOP_VOLUNTARY;
+ sample.event.type = SAMPLE_EVENT_NONE;
if (type & 0x80)
in_deco &= ~SAFETYSTOP;
else
in_deco |= SAFETYSTOP;
break;
case 0x01: // Mandatory Safety Stop - odd concept; model as deco stop
- sample.event.type = SAMPLE_EVENT_SAFETYSTOP_MANDATORY;
+ sample.event.type = SAMPLE_EVENT_NONE;
if (type & 0x80)
in_deco &= ~DECOSTOP;
else
in_deco |= DECOSTOP;
break;
case 0x02: // Deep Safety Stop
- sample.event.type = SAMPLE_EVENT_DEEPSTOP;
+ sample.event.type = SAMPLE_EVENT_NONE;
if (type & 0x80)
in_deco &= ~DEEPSTOP;
else
in_deco |= DEEPSTOP;
break;
case 0x03: // Deco
- sample.event.type = SAMPLE_EVENT_DECOSTOP;
+ sample.event.type = SAMPLE_EVENT_NONE;
if (type & 0x80)
in_deco &= ~DECOSTOP;
else
@@ -665,14 +665,14 @@ suunto_d9_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t ca
sample.event.type = SAMPLE_EVENT_TISSUELEVEL;
break;
case 0x13: // Deep Safety Stop
- sample.event.type = SAMPLE_EVENT_DEEPSTOP;
+ sample.event.type = SAMPLE_EVENT_NONE;
if (type & 0x80)
in_deco &= ~DEEPSTOP;
else
in_deco |= DEEPSTOP;
break;
case 0x14: // Mandatory Safety Stop - again, model as deco stop
- sample.event.type = SAMPLE_EVENT_SAFETYSTOP_MANDATORY;
+ sample.event.type = SAMPLE_EVENT_NONE;
if (type & 0x80)
in_deco &= ~DECOSTOP;
else
diff --git a/src/suunto_eonsteel.c b/src/suunto_eonsteel.c
index 50f800b..fe88c6f 100644
--- a/src/suunto_eonsteel.c
+++ b/src/suunto_eonsteel.c
@@ -140,7 +140,7 @@ static int receive_packet(suunto_eonsteel_device_t *eon, unsigned char *buffer,
return -1;
}
if (transferred != PACKET_SIZE) {
- ERROR(eon->base.context, "incomplete read interrupt transfer (got %d, expected %d)", transferred, PACKET_SIZE);
+ ERROR(eon->base.context, "incomplete read interrupt transfer (got %zu, expected %d)", transferred, PACKET_SIZE);
return -1;
}
if (buf[0] != 0x3f) {
diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c
index cff2575..5989060 100644
--- a/src/suunto_eonsteel_parser.c
+++ b/src/suunto_eonsteel_parser.c
@@ -234,7 +234,7 @@ static int fill_in_group_details(suunto_eonsteel_parser_t *eon, struct type_desc
}
base = eon->type_desc + index;
if (!base->desc) {
- ERROR(eon->base.context, "Group type descriptor '%s' has undescribed index %d", desc->desc, index);
+ ERROR(eon->base.context, "Group type descriptor '%s' has undescribed index %ld", desc->desc, index);
break;
}
if (!base->size) {
@@ -262,7 +262,7 @@ static int fill_in_group_details(suunto_eonsteel_parser_t *eon, struct type_desc
grp = end+1;
continue;
default:
- ERROR(eon->base.context, "Group type descriptor '%s' has unparseable index %d", desc->desc, index);
+ ERROR(eon->base.context, "Group type descriptor '%s' has unparseable index %ld", desc->desc, index);
return -1;
}
}
diff --git a/src/usbhid.c b/src/usbhid.c
index 44c0886..0a93824 100644
--- a/src/usbhid.c
+++ b/src/usbhid.c
@@ -346,7 +346,7 @@ dc_usbhid_read (dc_usbhid_t *usbhid, void *data, size_t size, size_t *actual)
if (usbhid == NULL) {
status = DC_STATUS_INVALIDARGS;
- goto out;
+ goto out_invalidargs;
}
#if defined(HAVE_LIBUSB) && !defined(__APPLE__)
@@ -369,6 +369,7 @@ dc_usbhid_read (dc_usbhid_t *usbhid, void *data, size_t size, size_t *actual)
out:
HEXDUMP (usbhid->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes);
+out_invalidargs:
if (actual)
*actual = nbytes;
@@ -387,7 +388,7 @@ dc_usbhid_write (dc_usbhid_t *usbhid, const void *data, size_t size, size_t *act
if (usbhid == NULL) {
status = DC_STATUS_INVALIDARGS;
- goto out;
+ goto out_invalidargs;
}
#if defined(HAVE_LIBUSB) && !defined(__APPLE__)
@@ -410,6 +411,7 @@ dc_usbhid_write (dc_usbhid_t *usbhid, const void *data, size_t size, size_t *act
out:
HEXDUMP (usbhid->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes);
+out_invalidargs:
if (actual)
*actual = nbytes;
diff --git a/src/uwatec_memomouse_parser.c b/src/uwatec_memomouse_parser.c
index d03d31b..e5c66f9 100644
--- a/src/uwatec_memomouse_parser.c
+++ b/src/uwatec_memomouse_parser.c
@@ -243,6 +243,16 @@ uwatec_memomouse_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
gasmix_previous = gasmix;
}
+ // NDL / Deco
+ if (warnings & 0x01) {
+ sample.deco.type = DC_DECO_DECOSTOP;
+ } else {
+ sample.deco.type = DC_DECO_NDL;
+ }
+ sample.deco.time = 0;
+ sample.deco.depth = 0.0;
+ if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
+
// Warnings
for (unsigned int i = 0; i < 6; ++i) {
if (warnings & (1 << i)) {
@@ -251,7 +261,7 @@ uwatec_memomouse_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
sample.event.value = 0;
switch (i) {
case 0: // Deco stop
- sample.event.type = SAMPLE_EVENT_DECOSTOP;
+ sample.event.type = SAMPLE_EVENT_NONE;
break;
case 1: // Remaining bottom time too short (Air series only)
sample.event.type = SAMPLE_EVENT_RBT;
@@ -269,7 +279,9 @@ uwatec_memomouse_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
sample.event.type = SAMPLE_EVENT_TRANSMITTER;
break;
}
- if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
+ if (sample.event.type != SAMPLE_EVENT_NONE) {
+ if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
+ }
}
}
diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c
index 71d69a0..8c6ce24 100644
--- a/src/uwatec_smart_parser.c
+++ b/src/uwatec_smart_parser.c
@@ -59,8 +59,7 @@
#define FRESH 1.000
#define SALT 1.025
-#define FREEDIVE1 0x00000080
-#define FREEDIVE2 0x00000200
+#define FREEDIVE 0x00000080
#define GAUGE 0x00001000
#define SALINITY 0x00100000
@@ -451,12 +450,8 @@ uwatec_smart_parser_cache (uwatec_smart_parser_t *parser)
// Get the freedive/gauge bits.
unsigned int freedive = 0;
unsigned int gauge = (settings & GAUGE) != 0;
- if (parser->model == ALADINTEC) {
- freedive = 0;
- } else if (parser->model == ALADINTEC2G) {
- freedive = (settings & FREEDIVE2) != 0;
- } else {
- freedive = (settings & FREEDIVE1) != 0;
+ if (parser->model != ALADINTEC && parser->model != ALADINTEC2G) {
+ freedive = (settings & FREEDIVE) != 0;
}
// Get the dive mode. The freedive bit needs to be checked
diff --git a/src/zeagle_n2ition3.c b/src/zeagle_n2ition3.c
index 516dd57..860238f 100644
--- a/src/zeagle_n2ition3.c
+++ b/src/zeagle_n2ition3.c
@@ -31,6 +31,7 @@
#include "checksum.h"
#include "array.h"
#include "ringbuffer.h"
+#include "rbstream.h"
#define ISINSTANCE(device) dc_device_isinstance((device), &zeagle_n2ition3_device_vtable)
@@ -352,16 +353,21 @@ zeagle_n2ition3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callba
progress.maximum = (RB_LOGBOOK_END - RB_LOGBOOK_BEGIN) * 2 + 8 + total;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
+ // 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);
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to create the ringbuffer stream.");
+ return rc;
+ }
+
// Memory buffer for the profile data.
unsigned char buffer[RB_PROFILE_END - RB_PROFILE_BEGIN] = {0};
- unsigned int available = 0;
- unsigned int remaining = total;
unsigned int offset = RB_PROFILE_END - RB_PROFILE_BEGIN;
idx = last;
previous = eop;
- unsigned int address = previous;
for (unsigned int i = 0; i < count; ++i) {
// Get the pointer to the profile data.
unsigned int current = array_uint16_le (config + 2 * idx);
@@ -369,50 +375,37 @@ 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 nbytes = available;
- while (nbytes < length) {
- if (address == RB_PROFILE_BEGIN)
- address = RB_PROFILE_END;
+ // Move to the begin of the current dive.
+ offset -= length;
- unsigned int len = SZ_PACKET;
- if (RB_PROFILE_BEGIN + len > address)
- len = address - RB_PROFILE_BEGIN; // End of ringbuffer.
- if (nbytes + len > remaining)
- len = remaining - nbytes; // End of profile.
-
- address -= len;
- offset -= len;
-
- // Read the memory page.
- rc = zeagle_n2ition3_device_read (abstract, address, buffer + offset, len);
- if (rc != DC_STATUS_SUCCESS) {
- ERROR (abstract->context, "Failed to read the memory page.");
- return rc;
- }
-
- // Update and emit a progress event.
- progress.current += len;
- device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
-
- nbytes += len;
+ // Read the dive.
+ rc = dc_rbstream_read (rbstream, &progress, buffer + offset, length);
+ if (rc != DC_STATUS_SUCCESS) {
+ ERROR (abstract->context, "Failed to read the dive.");
+ dc_rbstream_free (rbstream);
+ return rc;
+ }
+
+ unsigned char *p = buffer + offset;
+
+ if (memcmp (p, device->fingerprint, sizeof (device->fingerprint)) == 0) {
+ dc_rbstream_free (rbstream);
+ return DC_STATUS_SUCCESS;
+ }
+
+ if (callback && !callback (p, length, p, sizeof (device->fingerprint), userdata)) {
+ dc_rbstream_free (rbstream);
+ return DC_STATUS_SUCCESS;
}
- remaining -= length;
- available = nbytes - length;
previous = current;
- unsigned char *p = buffer + offset + available;
-
- if (memcmp (p, device->fingerprint, sizeof (device->fingerprint)) == 0)
- return DC_STATUS_SUCCESS;
-
- if (callback && !callback (p, length, p, sizeof (device->fingerprint), userdata))
- return DC_STATUS_SUCCESS;
-
if (idx == RB_LOGBOOK_BEGIN)
idx = RB_LOGBOOK_END;
idx--;
}
+ dc_rbstream_free (rbstream);
+
return DC_STATUS_SUCCESS;
}