Add support for reading a ringbuffer forwards
A dive computer typically writes its ringbuffer in the forward direction. Thus, when downloading the dives in reverse order (newest first), the ringbuffer needs to be read in the backward direction. However, some dive computers already re-arrange the data in the correct order, which means the data needs to be read in the opposite direction. To support this case without drastic changes in the logic, the rbstream implementation is extended to also support reading in the forward direction.
This commit is contained in:
parent
00b0169578
commit
9090f713b4
@ -965,7 +965,7 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
|
||||
last_start_address = base + array_uint32_le(data.config + layout->cf_last_log );
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
status = dc_rbstream_new (&rbstream, abstract, 1, layout->rbstream_size, layout->rb_profile_begin, layout->rb_profile_end, last_start_address);
|
||||
status = dc_rbstream_new (&rbstream, abstract, 1, layout->rbstream_size, layout->rb_profile_begin, layout->rb_profile_end, last_start_address, DC_RBSTREAM_BACKWARD);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
goto error;
|
||||
|
||||
@ -481,7 +481,7 @@ cressi_edy_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
dc_rbstream_t *rbstream = NULL;
|
||||
rc = dc_rbstream_new (&rbstream, abstract, SZ_PAGE, SZ_PACKET, layout->rb_profile_begin, layout->rb_profile_end, eop);
|
||||
rc = dc_rbstream_new (&rbstream, abstract, SZ_PAGE, SZ_PACKET, layout->rb_profile_begin, layout->rb_profile_end, eop, DC_RBSTREAM_BACKWARD);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
return rc;
|
||||
|
||||
@ -469,7 +469,7 @@ liquivision_lynx_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
dc_rbstream_t *rblogbook = NULL;
|
||||
status = dc_rbstream_new (&rblogbook, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END, rb_logbook_end);
|
||||
status = dc_rbstream_new (&rblogbook, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END, rb_logbook_end, DC_RBSTREAM_BACKWARD);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
goto error_free_logbook;
|
||||
@ -600,7 +600,7 @@ liquivision_lynx_device_foreach (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
dc_rbstream_t *rbprofile = NULL;
|
||||
status = dc_rbstream_new (&rbprofile, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_PROFILE_BEGIN, RB_PROFILE_END, rb_profile_end);
|
||||
status = dc_rbstream_new (&rbprofile, abstract, SEGMENTSIZE, SEGMENTSIZE, RB_PROFILE_BEGIN, RB_PROFILE_END, rb_profile_end, DC_RBSTREAM_BACKWARD);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
goto error_free_profile;
|
||||
|
||||
@ -686,7 +686,7 @@ mares_iconhd_device_foreach_raw (dc_device_t *abstract, dc_dive_callback_t callb
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
dc_rbstream_t *rbstream = NULL;
|
||||
rc = dc_rbstream_new (&rbstream, abstract, 1, device->packetsize, layout->rb_profile_begin, layout->rb_profile_end, eop);
|
||||
rc = dc_rbstream_new (&rbstream, abstract, 1, device->packetsize, layout->rb_profile_begin, layout->rb_profile_end, eop, DC_RBSTREAM_BACKWARD);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
return rc;
|
||||
|
||||
@ -327,7 +327,7 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
dc_rbstream_t *rbstream = NULL;
|
||||
rc = dc_rbstream_new (&rbstream, abstract, PAGESIZE, PAGESIZE * device->multipage, layout->rb_logbook_begin, layout->rb_logbook_end, rb_logbook_end);
|
||||
rc = dc_rbstream_new (&rbstream, abstract, PAGESIZE, PAGESIZE * device->multipage, layout->rb_logbook_begin, layout->rb_logbook_end, rb_logbook_end, DC_RBSTREAM_BACKWARD);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
return rc;
|
||||
@ -489,7 +489,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
dc_rbstream_t *rbstream = NULL;
|
||||
rc = dc_rbstream_new (&rbstream, abstract, PAGESIZE, PAGESIZE * device->multipage, layout->rb_profile_begin, layout->rb_profile_end, rb_profile_end);
|
||||
rc = dc_rbstream_new (&rbstream, abstract, PAGESIZE, PAGESIZE * device->multipage, layout->rb_profile_begin, layout->rb_profile_end, rb_profile_end, DC_RBSTREAM_BACKWARD);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
return rc;
|
||||
|
||||
@ -28,11 +28,13 @@
|
||||
|
||||
struct dc_rbstream_t {
|
||||
dc_device_t *device;
|
||||
dc_rbstream_direction_t direction;
|
||||
unsigned int pagesize;
|
||||
unsigned int packetsize;
|
||||
unsigned int begin;
|
||||
unsigned int end;
|
||||
unsigned int address;
|
||||
unsigned int offset;
|
||||
unsigned int available;
|
||||
unsigned int skip;
|
||||
unsigned char cache[];
|
||||
@ -53,7 +55,7 @@ iceil (unsigned int x, unsigned int n)
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_rbstream_new (dc_rbstream_t **out, dc_device_t *device, unsigned int pagesize, unsigned int packetsize, unsigned int begin, unsigned int end, unsigned int address)
|
||||
dc_rbstream_new (dc_rbstream_t **out, dc_device_t *device, unsigned int pagesize, unsigned int packetsize, unsigned int begin, unsigned int end, unsigned int address, dc_rbstream_direction_t direction)
|
||||
{
|
||||
dc_rbstream_t *rbstream = NULL;
|
||||
|
||||
@ -104,27 +106,31 @@ dc_rbstream_new (dc_rbstream_t **out, dc_device_t *device, unsigned int pagesize
|
||||
}
|
||||
|
||||
rbstream->device = device;
|
||||
rbstream->direction = direction;
|
||||
rbstream->pagesize = pagesize;
|
||||
rbstream->packetsize = packetsize;
|
||||
rbstream->begin = begin;
|
||||
rbstream->end = end;
|
||||
rbstream->address = iceil(address, pagesize);
|
||||
if (direction == DC_RBSTREAM_FORWARD) {
|
||||
rbstream->address = ifloor(address, pagesize);
|
||||
rbstream->skip = address - rbstream->address;
|
||||
} else {
|
||||
rbstream->address = iceil(address, pagesize);
|
||||
rbstream->skip = rbstream->address - address;
|
||||
}
|
||||
rbstream->offset = 0;
|
||||
rbstream->available = 0;
|
||||
rbstream->skip = rbstream->address - address;
|
||||
|
||||
*out = rbstream;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_rbstream_read (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsigned char data[], unsigned int size)
|
||||
static dc_status_t
|
||||
dc_rbstream_read_backward (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsigned char data[], unsigned int size)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
|
||||
if (rbstream == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
unsigned int offset = size;
|
||||
while (nbytes < size) {
|
||||
@ -171,6 +177,73 @@ dc_rbstream_read (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsign
|
||||
return rc;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
dc_rbstream_read_forward (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsigned char data[], unsigned int size)
|
||||
{
|
||||
dc_status_t rc = DC_STATUS_SUCCESS;
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
while (nbytes < size) {
|
||||
if (rbstream->available == 0) {
|
||||
// Handle the ringbuffer wrap point.
|
||||
if (rbstream->address == rbstream->end)
|
||||
rbstream->address = rbstream->begin;
|
||||
|
||||
// Calculate the packet size.
|
||||
unsigned int len = rbstream->packetsize;
|
||||
if (rbstream->address + len > rbstream->end)
|
||||
len = rbstream->end - rbstream->address;
|
||||
|
||||
// Calculate the excess number of bytes.
|
||||
unsigned int extra = rbstream->packetsize - len;
|
||||
|
||||
// Read the packet into the cache.
|
||||
rc = dc_device_read (rbstream->device, rbstream->address - extra, rbstream->cache, rbstream->packetsize);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return rc;
|
||||
|
||||
// Move to the begin of the next packet.
|
||||
rbstream->address += len;
|
||||
|
||||
rbstream->offset = extra + rbstream->skip;
|
||||
rbstream->available = len - rbstream->skip;
|
||||
rbstream->skip = 0;
|
||||
}
|
||||
|
||||
unsigned int length = rbstream->available;
|
||||
if (nbytes + length > size)
|
||||
length = size - nbytes;
|
||||
|
||||
memcpy (data + nbytes, rbstream->cache + rbstream->offset, length);
|
||||
|
||||
rbstream->offset += length;
|
||||
rbstream->available -= length;
|
||||
|
||||
// Update and emit a progress event.
|
||||
if (progress) {
|
||||
progress->current += length;
|
||||
device_event_emit (rbstream->device, DC_EVENT_PROGRESS, progress);
|
||||
}
|
||||
|
||||
nbytes += length;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_rbstream_read (dc_rbstream_t *rbstream, dc_event_progress_t *progress, unsigned char data[], unsigned int size)
|
||||
{
|
||||
if (rbstream == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
if (rbstream->direction == DC_RBSTREAM_FORWARD) {
|
||||
return dc_rbstream_read_forward (rbstream, progress, data, size);
|
||||
} else {
|
||||
return dc_rbstream_read_backward (rbstream, progress, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
dc_rbstream_free (dc_rbstream_t *rbstream)
|
||||
{
|
||||
|
||||
@ -33,6 +33,14 @@ extern "C" {
|
||||
*/
|
||||
typedef struct dc_rbstream_t dc_rbstream_t;
|
||||
|
||||
/**
|
||||
* The ringbuffer read direction.
|
||||
*/
|
||||
typedef enum dc_rbstream_direction_t {
|
||||
DC_RBSTREAM_FORWARD,
|
||||
DC_RBSTREAM_BACKWARD
|
||||
} dc_rbstream_direction_t;
|
||||
|
||||
/**
|
||||
* Create a new ringbuffer stream.
|
||||
*
|
||||
@ -43,11 +51,12 @@ typedef struct dc_rbstream_t dc_rbstream_t;
|
||||
* @param[in] begin The ringbuffer begin address.
|
||||
* @param[in] end The ringbuffer end address.
|
||||
* @param[in] address The stream start address.
|
||||
* @param[in] direction The ringbuffer read direction.
|
||||
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
|
||||
* on failure.
|
||||
*/
|
||||
dc_status_t
|
||||
dc_rbstream_new (dc_rbstream_t **rbstream, dc_device_t *device, unsigned int pagesize, unsigned int packetsize, unsigned int begin, unsigned int end, unsigned int address);
|
||||
dc_rbstream_new (dc_rbstream_t **rbstream, dc_device_t *device, unsigned int pagesize, unsigned int packetsize, unsigned int begin, unsigned int end, unsigned int address, dc_rbstream_direction_t direction);
|
||||
|
||||
/**
|
||||
* Read data from the ringbuffer stream.
|
||||
|
||||
@ -546,7 +546,7 @@ seac_screen_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback,
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
dc_rbstream_t *rbstream = NULL;
|
||||
status = dc_rbstream_new (&rbstream, abstract, SZ_READ, SZ_READ, RB_PROFILE_BEGIN, RB_PROFILE_END, eop);
|
||||
status = dc_rbstream_new (&rbstream, abstract, SZ_READ, SZ_READ, RB_PROFILE_BEGIN, RB_PROFILE_END, eop, DC_RBSTREAM_BACKWARD);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
goto error_free_profile;
|
||||
|
||||
@ -307,7 +307,7 @@ suunto_common2_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
dc_rbstream_t *rbstream = NULL;
|
||||
rc = dc_rbstream_new (&rbstream, abstract, 1, SZ_PACKET, layout->rb_profile_begin, layout->rb_profile_end, end);
|
||||
rc = dc_rbstream_new (&rbstream, abstract, 1, SZ_PACKET, layout->rb_profile_begin, layout->rb_profile_end, end, DC_RBSTREAM_BACKWARD);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
return rc;
|
||||
|
||||
@ -326,7 +326,7 @@ zeagle_n2ition3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callba
|
||||
|
||||
// Create the ringbuffer stream.
|
||||
dc_rbstream_t *rbstream = NULL;
|
||||
rc = dc_rbstream_new (&rbstream, abstract, 1, SZ_PACKET, RB_PROFILE_BEGIN, RB_PROFILE_END, eop);
|
||||
rc = dc_rbstream_new (&rbstream, abstract, 1, SZ_PACKET, RB_PROFILE_BEGIN, RB_PROFILE_END, eop, DC_RBSTREAM_BACKWARD);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to create the ringbuffer stream.");
|
||||
return rc;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user