Merge git://git.libdivecomputer.org/libdivecomputer into Subsurface-branch

Merge upstream libdivecomputer changes from Jef Driesen.

No major changes and no conflicts except for a trivial one where Jef had
marked a couple of private functions 'static' and our versions had
extended the argument lists of those functions.

This just updates to the current upstream state of libdivecomputer,
where the bulk of the changes come mainly from the new ringbuffer helper
code, but there are various other small misc fixes and cleanups.

* git://git.libdivecomputer.org/libdivecomputer:
  Disable the deco events
  Replace the deco events with a deco sample
  Report errors from the close function
  Mark the private function as static
  Fix a bug in the tank pressure samples
  Disable freedive mode for the Uwatec Aladin Tec 2G
  Mark the private function as static
  Fix some compiler warnings
  Fix some more null pointer dereferences
  Use a more efficient download algorithm
  Use the new ringbuffer stream
  Add a common ringbuffer reading algorithm
  Improve the robustness of the IrDA I/O code
  Fix a few null pointer dereferences
  Fix the number of gas mixes
  Always use the sample timestamp as the base value
This commit is contained in:
Linus Torvalds 2017-04-12 08:24:04 -07:00
commit b04f393b97
34 changed files with 659 additions and 498 deletions

View File

@ -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);

View File

@ -362,6 +362,10 @@
RelativePath="..\src\parser.c"
>
</File>
<File
RelativePath="..\src\rbstream.c"
>
</File>
<File
RelativePath="..\src\reefnet_sensus.c"
>
@ -680,6 +684,10 @@
RelativePath="..\include\libdivecomputer\parser.h"
>
</File>
<File
RelativePath="..\src\rbstream.h"
>
</File>
<File
RelativePath="..\include\libdivecomputer\reefnet.h"
>

View File

@ -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 \

View File

@ -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));
// Read the dive.
rc = dc_rbstream_read (rbstream, &progress, buffer + offset, length);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to read the memory page.");
free(buffer);
ERROR (abstract->context, "Failed to read the dive.");
dc_rbstream_free (rbstream);
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;
}
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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -36,6 +36,7 @@
#include <linux/irda.h> // irda
#include <sys/select.h> // select
#include <sys/ioctl.h> // ioctl
#include <sys/time.h>
#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;
}
struct timeval tv;
if (device->timeout >= 0) {
tv.tv_sec = (device->timeout / 1000);
tv.tv_usec = (device->timeout % 1000) * 1000;
goto out_invalidargs;
}
while (nbytes < size) {
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));
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;

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}
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;

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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);
// 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;
nbytes += 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)) {
if (array_isequal (logbooks + offset, layout->rb_logbook_entry_size, 0xFF)) {
WARNING (abstract->context, "Uninitialized logbook entries detected!");
begin = current + layout->rb_logbook_entry_size;
abort = 1;
offset += layout->rb_logbook_entry_size;
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;
if (memcmp (logbooks + offset, device->fingerprint, layout->rb_logbook_entry_size) == 0) {
offset += layout->rb_logbook_entry_size;
break;
}
}
// Stop reading pages too.
if (abort)
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);
// 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;
}
// Update and emit a progress event.
progress->current += len;
device_event_emit (abstract, DC_EVENT_PROGRESS, progress);
nbytes += len;
}
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;

View File

@ -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);

View File

@ -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);

View File

@ -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;

176
src/rbstream.c Normal file
View File

@ -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 <stdlib.h>
#include <string.h>
#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;
}

78
src/rbstream.h Normal file
View File

@ -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 <libdivecomputer/device.h>
#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 */

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
// Read the dive.
rc = dc_rbstream_read (rbstream, &progress, data + offset, size);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to read the memory.");
ERROR (abstract->context, "Failed to read the dive.");
dc_rbstream_free (rbstream);
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;
}
// 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;

View File

@ -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

View File

@ -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) {

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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,9 +279,11 @@ uwatec_memomouse_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba
sample.event.type = SAMPLE_EVENT_TRANSMITTER;
break;
}
if (sample.event.type != SAMPLE_EVENT_NONE) {
if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
}
}
}
if (time % 60 == 0) {
sample.vendor.type = SAMPLE_VENDOR_UWATEC_ALADIN;

View File

@ -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

View File

@ -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);
// Read the dive.
rc = dc_rbstream_read (rbstream, &progress, buffer + offset, length);
if (rc != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to read the memory page.");
ERROR (abstract->context, "Failed to read the dive.");
dc_rbstream_free (rbstream);
return rc;
}
// Update and emit a progress event.
progress.current += len;
device_event_emit (abstract, DC_EVENT_PROGRESS, &progress);
unsigned char *p = buffer + offset;
nbytes += len;
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;
}