diff --git a/src/cressi_edy.c b/src/cressi_edy.c index 0dbe456..b28b423 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) { @@ -492,41 +479,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 +509,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 +517,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 +537,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/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/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/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; }