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