diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 0c63e16..69ab7d5 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -86,6 +86,8 @@ static const oceanic_common_device_vtable_t oceanic_atom2_device_vtable = { NULL, /* timesync */ oceanic_atom2_device_close /* close */ }, + oceanic_common_device_devinfo, + oceanic_common_device_pointers, oceanic_common_device_logbook, oceanic_common_device_profile, }; @@ -98,10 +100,11 @@ static const oceanic_common_layout_t aeris_f10_layout = { 0x0100, /* rb_logbook_begin */ 0x0D80, /* rb_logbook_end */ 32, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0D80, /* rb_profile_begin */ 0x10000, /* rb_profile_end */ 0, /* pt_mode_global */ - 2, /* pt_mode_logbook */ + 3, /* pt_mode_logbook */ 0, /* pt_mode_serial */ }; @@ -113,10 +116,11 @@ static const oceanic_common_layout_t aeris_f11_layout = { 0x0100, /* rb_logbook_begin */ 0x0D80, /* rb_logbook_end */ 32, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0D80, /* rb_profile_begin */ 0x20000, /* rb_profile_end */ 0, /* pt_mode_global */ - 3, /* pt_mode_logbook */ + 2, /* pt_mode_logbook */ 0, /* pt_mode_serial */ }; @@ -128,6 +132,7 @@ static const oceanic_common_layout_t oceanic_default_layout = { 0x0240, /* rb_logbook_begin */ 0x0A40, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0A40, /* rb_profile_begin */ 0x10000, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -143,6 +148,7 @@ static const oceanic_common_layout_t oceanic_atom1_layout = { 0x0240, /* rb_logbook_begin */ 0x0440, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0440, /* rb_profile_begin */ 0x8000, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -158,6 +164,7 @@ static const oceanic_common_layout_t oceanic_atom2a_layout = { 0x0240, /* rb_logbook_begin */ 0x0A40, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0A40, /* rb_profile_begin */ 0xFE00, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -173,6 +180,7 @@ static const oceanic_common_layout_t oceanic_atom2b_layout = { 0x0240, /* rb_logbook_begin */ 0x0A40, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0A40, /* rb_profile_begin */ 0xFE00, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -188,6 +196,7 @@ static const oceanic_common_layout_t oceanic_atom2c_layout = { 0x0240, /* rb_logbook_begin */ 0x0A40, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0A40, /* rb_profile_begin */ 0xFFF0, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -203,6 +212,7 @@ static const oceanic_common_layout_t sherwood_wisdom_layout = { 0x03D0, /* rb_logbook_begin */ 0x0A40, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0A40, /* rb_profile_begin */ 0xFE00, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -218,6 +228,7 @@ static const oceanic_common_layout_t oceanic_proplus3_layout = { 0x03E0, /* rb_logbook_begin */ 0x0A40, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0A40, /* rb_profile_begin */ 0xFE00, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -233,6 +244,7 @@ static const oceanic_common_layout_t tusa_zenair_layout = { 0x0240, /* rb_logbook_begin */ 0x0A40, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0A40, /* rb_profile_begin */ 0xFE00, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -248,6 +260,7 @@ static const oceanic_common_layout_t oceanic_oc1_layout = { 0x0240, /* rb_logbook_begin */ 0x0A40, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0A40, /* rb_profile_begin */ 0x1FE00, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -263,6 +276,7 @@ static const oceanic_common_layout_t oceanic_oci_layout = { 0x10C0, /* rb_logbook_begin */ 0x1400, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x1400, /* rb_profile_begin */ 0x1FE00, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -278,6 +292,7 @@ static const oceanic_common_layout_t oceanic_atom3_layout = { 0x0400, /* rb_logbook_begin */ 0x0A40, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0A40, /* rb_profile_begin */ 0x1FE00, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -293,6 +308,7 @@ static const oceanic_common_layout_t oceanic_vt4_layout = { 0x0420, /* rb_logbook_begin */ 0x0A40, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0A40, /* rb_profile_begin */ 0x1FE00, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -308,6 +324,7 @@ static const oceanic_common_layout_t hollis_tx1_layout = { 0x0780, /* rb_logbook_begin */ 0x1000, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x1000, /* rb_profile_begin */ 0x40000, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -323,6 +340,7 @@ static const oceanic_common_layout_t oceanic_veo1_layout = { 0x0400, /* rb_logbook_begin */ 0x0400, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0400, /* rb_profile_begin */ 0x0400, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -338,6 +356,7 @@ static const oceanic_common_layout_t oceanic_reactpro_layout = { 0x0400, /* rb_logbook_begin */ 0x0600, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0600, /* rb_profile_begin */ 0xFE00, /* rb_profile_end */ 1, /* pt_mode_global */ @@ -353,6 +372,7 @@ static const oceanic_common_layout_t oceanic_proplusx_layout = { 0x1000, /* rb_logbook_begin */ 0x10000, /* rb_logbook_end */ 16, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x40000, /* rb_profile_begin */ 0x440000, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -368,6 +388,7 @@ static const oceanic_common_layout_t aqualung_i770r_layout = { 0x2000, /* rb_logbook_begin */ 0x10000, /* rb_logbook_end */ 16, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x40000, /* rb_profile_begin */ 0x640000, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -383,6 +404,7 @@ static const oceanic_common_layout_t aeris_a300cs_layout = { 0x0900, /* rb_logbook_begin */ 0x1000, /* rb_logbook_end */ 16, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x1000, /* rb_profile_begin */ 0x3FE00, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -398,6 +420,7 @@ static const oceanic_common_layout_t aqualung_i450t_layout = { 0x10C0, /* rb_logbook_begin */ 0x1400, /* rb_logbook_end */ 16, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x1400, /* rb_profile_begin */ 0x3FE00, /* rb_profile_end */ 0, /* pt_mode_global */ diff --git a/src/oceanic_common.c b/src/oceanic_common.c index e79406a..1e00047 100644 --- a/src/oceanic_common.c +++ b/src/oceanic_common.c @@ -32,72 +32,59 @@ #define VTABLE(abstract) ((const oceanic_common_device_vtable_t *) abstract->vtable) -#define RB_LOGBOOK_DISTANCE(a,b,l) ringbuffer_distance (a, b, DC_RINGBUFFER_FULL, l->rb_logbook_begin, l->rb_logbook_end) -#define RB_LOGBOOK_INCR(a,b,l) ringbuffer_increment (a, b, l->rb_logbook_begin, l->rb_logbook_end) +#define RB_LOGBOOK_DISTANCE(a,b,l,m) ringbuffer_distance (a, b, m, l->rb_logbook_begin, l->rb_logbook_end) -#define RB_PROFILE_DISTANCE(a,b,l) ringbuffer_distance (a, b, DC_RINGBUFFER_EMPTY, l->rb_profile_begin, l->rb_profile_end) -#define RB_PROFILE_INCR(a,b,l) ringbuffer_increment (a, b, l->rb_profile_begin, l->rb_profile_end) +#define RB_PROFILE_DISTANCE(a,b,l,m) ringbuffer_distance (a, b, m, l->rb_profile_begin, l->rb_profile_end) #define INVALID 0 -static unsigned int -get_profile_first (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int pagesize) +static dc_status_t +oceanic_common_device_get_profile (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int *begin, unsigned int *end) { - unsigned int value; + assert (layout != NULL); + assert (begin != NULL && end != NULL); + // Get the pagesize + unsigned int pagesize = layout->highmem ? 16 * PAGESIZE : PAGESIZE; + + // Get the profile pointers. + unsigned int first = 0, last = 0; if (layout->pt_mode_logbook == 0) { - value = array_uint16_le (data + 5); + first = array_uint16_le (data + 5); + last = array_uint16_le (data + 6) >> 4; } else if (layout->pt_mode_logbook == 1) { - value = array_uint16_le (data + 4); - } else if (layout->pt_mode_logbook == 3) { - value = array_uint16_le (data + 16); - } else { - return array_uint16_le (data + 16); + first = array_uint16_le (data + 4); + last = array_uint16_le (data + 6); + } else if (layout->pt_mode_logbook == 2 || layout->pt_mode_logbook == 3) { + first = array_uint16_le (data + 16); + last = array_uint16_le (data + 18); } - unsigned int npages = (layout->memsize - layout->highmem) / pagesize; - if (npages > 0x4000) { - value &= 0x7FFF; - } else if (npages > 0x2000) { - value &= 0x3FFF; - } else if (npages > 0x1000) { - value &= 0x1FFF; - } else { - value &= 0x0FFF; + // Convert pages to bytes. + if (layout->pt_mode_logbook < 3) { + unsigned int npages = (layout->memsize - layout->highmem) / pagesize; + if (npages > 0x4000) { + first &= 0x7FFF; + last &= 0x7FFF; + } else if (npages > 0x2000) { + first &= 0x3FFF; + last &= 0x3FFF; + } else if (npages > 0x1000) { + first &= 0x1FFF; + last &= 0x1FFF; + } else { + first &= 0x0FFF; + last &= 0x0FFF; + } + + first *= pagesize; + last *= pagesize; } - return layout->highmem + value * pagesize; -} + *begin = layout->highmem + first; + *end = layout->highmem + last + pagesize; - -static unsigned int -get_profile_last (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int pagesize) -{ - unsigned int value; - - if (layout->pt_mode_logbook == 0) { - value = array_uint16_le (data + 6) >> 4; - } else if (layout->pt_mode_logbook == 1) { - value = array_uint16_le (data + 6); - } else if (layout->pt_mode_logbook == 3) { - value = array_uint16_le (data + 18); - } else { - return array_uint16_le(data + 18); - } - - unsigned int npages = (layout->memsize - layout->highmem) / pagesize; - - if (npages > 0x4000) { - value &= 0x7FFF; - } else if (npages > 0x2000) { - value &= 0x3FFF; - } else if (npages > 0x1000) { - value &= 0x1FFF; - } else { - value &= 0x0FFF; - } - - return layout->highmem + value * pagesize; + return DC_STATUS_SUCCESS; } @@ -206,11 +193,11 @@ oceanic_common_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) return DC_STATUS_NOMEMORY; } - // 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 device info. + status = VTABLE(abstract)->devinfo (abstract, NULL); + if (status != DC_STATUS_SUCCESS) { + return status; + } // Download the memory dump. status = device_dump_read (abstract, 0, dc_buffer_get_data (buffer), @@ -219,8 +206,43 @@ oceanic_common_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) return status; } + return status; +} + + +dc_status_t +oceanic_common_device_devinfo (dc_device_t *abstract, dc_event_progress_t *progress) +{ + dc_status_t status = DC_STATUS_SUCCESS; + oceanic_common_device_t *device = (oceanic_common_device_t *) abstract; + + assert (device != NULL); + assert (device->layout != NULL); + + const oceanic_common_layout_t *layout = device->layout; + + // Read the device id. + unsigned char id[PAGESIZE] = {0}; + status = dc_device_read (abstract, layout->cf_devinfo, id, sizeof (id)); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to read the memory page."); + return status; + } + + // Update and emit a progress event. + if (progress) { + progress->current += PAGESIZE; + progress->maximum += PAGESIZE; + 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); + // Emit a device info event. - unsigned char *id = dc_buffer_get_data (buffer) + layout->cf_devinfo; dc_event_devinfo_t devinfo; devinfo.model = array_uint16_be (id + 8); devinfo.firmware = device->firmware; @@ -240,7 +262,51 @@ oceanic_common_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) dc_status_t -oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook) +oceanic_common_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress, + unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, + unsigned int *rb_profile_begin, unsigned int *rb_profile_end) +{ + dc_status_t status = DC_STATUS_SUCCESS; + oceanic_common_device_t *device = (oceanic_common_device_t *) abstract; + + assert (device != NULL); + assert (device->layout != NULL); + assert (rb_logbook_begin != NULL && rb_logbook_end != NULL); + assert (rb_profile_begin != NULL && rb_profile_end != NULL); + + const oceanic_common_layout_t *layout = device->layout; + + // Read the pointer data. + unsigned char pointers[PAGESIZE] = {0}; + status = dc_device_read (abstract, layout->cf_pointers, pointers, sizeof (pointers)); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to read the memory page."); + return status; + } + + // Update and emit a progress event. + if (progress) { + progress->current += PAGESIZE; + progress->maximum += PAGESIZE; + device_event_emit (abstract, DC_EVENT_PROGRESS, progress); + } + + // Get the pointers. + unsigned int rb_logbook_first = array_uint16_le (pointers + 4); + unsigned int rb_logbook_last = array_uint16_le (pointers + 6); + unsigned int rb_profile_first = array_uint16_le (pointers + 8); + unsigned int rb_profile_last = array_uint16_le (pointers + 10); + + *rb_logbook_begin = rb_logbook_first; + *rb_logbook_end = rb_logbook_last + (layout->pt_mode_global == 0 ? layout->rb_logbook_entry_size : 0); + *rb_profile_begin = rb_profile_first; + *rb_profile_end = rb_profile_last; + + return status; +} + +dc_status_t +oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end) { oceanic_common_device_t *device = (oceanic_common_device_t *) abstract; dc_status_t rc = DC_STATUS_SUCCESS; @@ -256,37 +322,30 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr if (!dc_buffer_clear (logbook)) return DC_STATUS_NOMEMORY; - // For devices without a logbook ringbuffer, downloading dives isn't - // possible. This is not considered a fatal error, but handled as if there - // are no dives present. - if (layout->rb_logbook_begin == layout->rb_logbook_end) { - return DC_STATUS_SUCCESS; - } - - // Read the pointer data. - unsigned char pointers[PAGESIZE] = {0}; - rc = dc_device_read (abstract, layout->cf_pointers, pointers, sizeof (pointers)); - if (rc != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to read the memory page."); - return rc; - } - - // Get the logbook pointers. - unsigned int rb_logbook_first = array_uint16_le (pointers + 4); - unsigned int rb_logbook_last = array_uint16_le (pointers + 6); - if (rb_logbook_last < layout->rb_logbook_begin || - rb_logbook_last >= layout->rb_logbook_end) + // Validate the logbook pointers. + unsigned int rb_logbook_begin = begin; + unsigned int rb_logbook_end = end; + if (rb_logbook_begin < layout->rb_logbook_begin || + rb_logbook_begin > layout->rb_logbook_end) { - ERROR (abstract->context, "Invalid logbook end pointer detected (0x%04x).", rb_logbook_last); - return DC_STATUS_DATAFORMAT; + ERROR (abstract->context, "Invalid logbook begin pointer detected (0x%04x).", rb_logbook_begin); + if (layout->rb_logbook_direction == 0) { + return DC_STATUS_DATAFORMAT; + } + // Fall back to downloading the entire logbook ringbuffer as + // workaround for an invalid logbook begin pointer! + rb_logbook_begin = rb_logbook_end; } - - // Calculate the end pointer. - unsigned int rb_logbook_end = 0; - if (layout->pt_mode_global == 0) { - rb_logbook_end = RB_LOGBOOK_INCR (rb_logbook_last, layout->rb_logbook_entry_size, layout); - } else { - rb_logbook_end = rb_logbook_last; + if (rb_logbook_end < layout->rb_logbook_begin || + rb_logbook_end > layout->rb_logbook_end) + { + ERROR (abstract->context, "Invalid logbook end pointer detected (0x%04x).", rb_logbook_end); + if (layout->rb_logbook_direction != 0) { + return DC_STATUS_DATAFORMAT; + } + // Fall back to downloading the entire logbook ringbuffer as + // workaround for an invalid logbook end pointer! + rb_logbook_end = rb_logbook_begin; } // Calculate the number of bytes. @@ -295,21 +354,9 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr // 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. - unsigned int rb_logbook_size = 0; - if (rb_logbook_first < layout->rb_logbook_begin || - rb_logbook_first >= layout->rb_logbook_end) - { - // Fall back to downloading the entire logbook ringbuffer as - // workaround for an invalid logbook begin pointer! - ERROR (abstract->context, "Invalid logbook begin pointer detected (0x%04x).", rb_logbook_first); - rb_logbook_size = layout->rb_logbook_end - layout->rb_logbook_begin; - } else { - rb_logbook_size = RB_LOGBOOK_DISTANCE (rb_logbook_first, rb_logbook_end, layout); - } + unsigned int rb_logbook_size = RB_LOGBOOK_DISTANCE (rb_logbook_begin, rb_logbook_end, layout, DC_RINGBUFFER_FULL); // Update and emit a progress event. - progress->current += PAGESIZE; - progress->maximum += PAGESIZE; progress->maximum -= (layout->rb_logbook_end - layout->rb_logbook_begin) - rb_logbook_size; device_event_emit (abstract, DC_EVENT_PROGRESS, progress); @@ -327,7 +374,11 @@ 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, DC_RBSTREAM_BACKWARD); + rc = dc_rbstream_new (&rbstream, abstract, + PAGESIZE, PAGESIZE * device->multipage, + layout->rb_logbook_begin, layout->rb_logbook_end, + layout->rb_logbook_direction ? rb_logbook_end : rb_logbook_begin, + layout->rb_logbook_direction ? DC_RBSTREAM_BACKWARD : DC_RBSTREAM_FORWARD); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to create the ringbuffer stream."); return rc; @@ -403,9 +454,6 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr const oceanic_common_layout_t *layout = device->layout; - // Get the pagesize - unsigned int pagesize = layout->highmem ? 16 * PAGESIZE : PAGESIZE; - // Cache the logbook pointer and size. const unsigned char *logbooks = dc_buffer_get_data (logbook); unsigned int rb_logbook_size = dc_buffer_get_size (logbook); @@ -413,6 +461,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr // Go through the logbook entries a first time, to get the end of // profile pointer and calculate the total amount of bytes in the // profile ringbuffer. + unsigned int rb_profile_begin = INVALID; unsigned int rb_profile_end = INVALID; unsigned int rb_profile_size = 0; @@ -434,22 +483,20 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr } // Get the profile pointers. - unsigned int rb_entry_first = get_profile_first (logbooks + entry, layout, pagesize); - unsigned int rb_entry_last = get_profile_last (logbooks + entry, layout, pagesize); - if (rb_entry_first < layout->rb_profile_begin || - rb_entry_first >= layout->rb_profile_end || - rb_entry_last < layout->rb_profile_begin || - rb_entry_last >= layout->rb_profile_end) + unsigned int rb_entry_begin = 0, rb_entry_end = 0; + oceanic_common_device_get_profile (logbooks + entry, layout, &rb_entry_begin, &rb_entry_end); + if (rb_entry_begin < layout->rb_profile_begin || + rb_entry_begin > layout->rb_profile_end || + rb_entry_end < layout->rb_profile_begin || + rb_entry_end > layout->rb_profile_end) { ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).", - rb_entry_first, rb_entry_last); + rb_entry_begin, rb_entry_end); status = DC_STATUS_DATAFORMAT; continue; } - // Calculate the end pointer and the number of bytes. - unsigned int rb_entry_end = RB_PROFILE_INCR (rb_entry_last, pagesize, layout); - unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_first, rb_entry_last, layout) + pagesize; + DEBUG (abstract->context, "Entry: %08x %08x", rb_entry_begin, rb_entry_end); // Take the end pointer of the most recent logbook entry as the // end of profile pointer. @@ -457,10 +504,12 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr rb_profile_end = previous = rb_entry_end; } + // Calculate the number of bytes. + unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_begin, rb_entry_end, layout, DC_RINGBUFFER_FULL); + // Skip gaps between the profiles. - unsigned int gap = 0; - if (rb_entry_end != previous) { - gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout); + unsigned int gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout, DC_RINGBUFFER_EMPTY); + if (gap) { WARNING (abstract->context, "Profiles are not continuous (%u bytes).", gap); } @@ -470,13 +519,18 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr break; } + // Update the profile begin pointer. + rb_profile_begin = rb_entry_begin; + // Update the total profile size. rb_profile_size += rb_entry_size + gap; remaining -= rb_entry_size + gap; - previous = rb_entry_first; + previous = rb_entry_begin; } + DEBUG (abstract->context, "Profile: %08x %08x", rb_profile_begin, rb_profile_end); + // At this point, we know the exact amount of data // that needs to be transfered for the profiles. progress->maximum -= (layout->rb_profile_end - layout->rb_profile_begin) - rb_profile_size; @@ -524,27 +578,27 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr } // Get the profile pointers. - unsigned int rb_entry_first = get_profile_first (logbooks + entry, layout, pagesize); - unsigned int rb_entry_last = get_profile_last (logbooks + entry, layout, pagesize); - if (rb_entry_first < layout->rb_profile_begin || - rb_entry_first >= layout->rb_profile_end || - rb_entry_last < layout->rb_profile_begin || - rb_entry_last >= layout->rb_profile_end) + unsigned int rb_entry_begin = 0, rb_entry_end = 0; + oceanic_common_device_get_profile (logbooks + entry, layout, &rb_entry_begin, &rb_entry_end); + if (rb_entry_begin < layout->rb_profile_begin || + rb_entry_begin > layout->rb_profile_end || + rb_entry_end < layout->rb_profile_begin || + rb_entry_end > layout->rb_profile_end) { ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).", - rb_entry_first, rb_entry_last); + rb_entry_begin, rb_entry_end); status = DC_STATUS_DATAFORMAT; continue; } - // Calculate the end pointer and the number of bytes. - unsigned int rb_entry_end = RB_PROFILE_INCR (rb_entry_last, pagesize, layout); - unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_first, rb_entry_last, layout) + pagesize; + DEBUG (abstract->context, "Entry: %08x %08x", rb_entry_begin, rb_entry_end); + + // Calculate the number of bytes. + unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_begin, rb_entry_end, layout, DC_RINGBUFFER_FULL); // Skip gaps between the profiles. - unsigned int gap = 0; - if (rb_entry_end != previous) { - gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout); + unsigned int gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout, DC_RINGBUFFER_EMPTY); + if (gap) { WARNING (abstract->context, "Profiles are not continuous (%u bytes).", gap); } @@ -566,7 +620,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr } remaining -= rb_entry_size + gap; - previous = rb_entry_first; + previous = rb_entry_begin; // Prepend the logbook entry to the profile data. The memory buffer is // large enough to store this entry. @@ -604,6 +658,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr dc_status_t oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata) { + dc_status_t rc = DC_STATUS_SUCCESS; oceanic_common_device_t *device = (oceanic_common_device_t *) abstract; assert (device != NULL); @@ -611,45 +666,37 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac const oceanic_common_layout_t *layout = device->layout; + // For devices without a logbook and profile ringbuffer, downloading dives + // isn't possible. This is not considered a fatal error, but handled as if + // there are no dives present. + if (layout->rb_logbook_begin == layout->rb_logbook_end && + layout->rb_profile_begin == layout->rb_profile_end) { + return DC_STATUS_SUCCESS; + } + // Enable progress notifications. dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; - progress.maximum = PAGESIZE + + progress.maximum = (layout->rb_logbook_end - layout->rb_logbook_begin) + (layout->rb_profile_end - layout->rb_profile_begin); 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 device id. - unsigned char id[PAGESIZE] = {0}; - dc_status_t rc = dc_device_read (abstract, layout->cf_devinfo, id, sizeof (id)); + // Read the device info. + rc = VTABLE(abstract)->devinfo (abstract, &progress); if (rc != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to read the memory page."); return rc; } - // Update and emit a progress event. - progress.current += PAGESIZE; - device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); + // Read the ringbuffer pointers. + unsigned int rb_logbook_begin = 0, rb_logbook_end = 0; + unsigned int rb_profile_begin = 0, rb_profile_end = 0; + rc = VTABLE(abstract)->pointers (abstract, &progress, &rb_logbook_begin, &rb_logbook_end, &rb_profile_begin, &rb_profile_end); + if (rc != DC_STATUS_SUCCESS) { + return rc; + } - // Emit a device info event. - dc_event_devinfo_t devinfo; - devinfo.model = array_uint16_be (id + 8); - devinfo.firmware = device->firmware; - if (layout->pt_mode_serial == 0) - devinfo.serial = array_convert_bcd2dec (id + 10, 3); - else if (layout->pt_mode_serial == 1) - devinfo.serial = array_convert_bin2dec (id + 11, 3); - else - devinfo.serial = - (id[11] & 0x0F) * 100000 + ((id[11] & 0xF0) >> 4) * 10000 + - (id[12] & 0x0F) * 1000 + ((id[12] & 0xF0) >> 4) * 100 + - (id[13] & 0x0F) * 10 + ((id[13] & 0xF0) >> 4) * 1; - device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); + DEBUG (abstract->context, "Logbook: %08x %08x", rb_logbook_begin, rb_logbook_end); + DEBUG (abstract->context, "Profile: %08x %08x", rb_profile_begin, rb_profile_end); // Memory buffer for the logbook data. dc_buffer_t *logbook = dc_buffer_new (0); @@ -658,7 +705,7 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac } // Download the logbook ringbuffer. - rc = VTABLE(abstract)->logbook (abstract, &progress, logbook); + rc = VTABLE(abstract)->logbook (abstract, &progress, logbook, rb_logbook_begin, rb_logbook_end); if (rc != DC_STATUS_SUCCESS) { dc_buffer_free (logbook); return rc; diff --git a/src/oceanic_common.h b/src/oceanic_common.h index 045dca4..b468b07 100644 --- a/src/oceanic_common.h +++ b/src/oceanic_common.h @@ -144,6 +144,7 @@ typedef struct oceanic_common_layout_t { unsigned int rb_logbook_begin; unsigned int rb_logbook_end; unsigned int rb_logbook_entry_size; + unsigned int rb_logbook_direction; // Profile ringbuffer unsigned int rb_profile_begin; unsigned int rb_profile_end; @@ -168,7 +169,9 @@ typedef struct oceanic_common_device_t { typedef struct oceanic_common_device_vtable_t { dc_device_vtable_t base; - dc_status_t (*logbook) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook); + dc_status_t (*devinfo) (dc_device_t *device, dc_event_progress_t *progress); + dc_status_t (*pointers) (dc_device_t *device, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end); + dc_status_t (*logbook) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end); dc_status_t (*profile) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata); } oceanic_common_device_vtable_t; @@ -186,7 +189,15 @@ void oceanic_common_device_init (oceanic_common_device_t *device); dc_status_t -oceanic_common_device_logbook (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook); +oceanic_common_device_devinfo (dc_device_t *device, dc_event_progress_t *progress); + +dc_status_t +oceanic_common_device_pointers (dc_device_t *device, dc_event_progress_t *progress, + unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, + unsigned int *rb_profile_begin, unsigned int *rb_profile_end); + +dc_status_t +oceanic_common_device_logbook (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end); dc_status_t oceanic_common_device_profile (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata); diff --git a/src/oceanic_veo250.c b/src/oceanic_veo250.c index 58a9ceb..f39b1cd 100644 --- a/src/oceanic_veo250.c +++ b/src/oceanic_veo250.c @@ -58,6 +58,8 @@ static const oceanic_common_device_vtable_t oceanic_veo250_device_vtable = { NULL, /* timesync */ oceanic_veo250_device_close /* close */ }, + oceanic_common_device_devinfo, + oceanic_common_device_pointers, oceanic_common_device_logbook, oceanic_common_device_profile, }; @@ -70,6 +72,7 @@ static const oceanic_common_layout_t oceanic_veo250_layout = { 0x0400, /* rb_logbook_begin */ 0x0600, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0600, /* rb_profile_begin */ 0x8000, /* rb_profile_end */ 1, /* pt_mode_global */ diff --git a/src/oceanic_vtpro.c b/src/oceanic_vtpro.c index d7e9882..b63c0fb 100644 --- a/src/oceanic_vtpro.c +++ b/src/oceanic_vtpro.c @@ -51,7 +51,8 @@ typedef struct oceanic_vtpro_device_t { oceanic_vtpro_protocol_t protocol; } oceanic_vtpro_device_t; -static dc_status_t oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook); +static dc_status_t oceanic_vtpro_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end); +static dc_status_t oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end); static dc_status_t oceanic_vtpro_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); static dc_status_t oceanic_vtpro_device_close (dc_device_t *abstract); @@ -67,6 +68,8 @@ static const oceanic_common_device_vtable_t oceanic_vtpro_device_vtable = { NULL, /* timesync */ oceanic_vtpro_device_close /* close */ }, + oceanic_common_device_devinfo, + oceanic_vtpro_device_pointers, oceanic_vtpro_device_logbook, oceanic_common_device_profile, }; @@ -79,6 +82,7 @@ static const oceanic_common_layout_t oceanic_vtpro_layout = { 0x0240, /* rb_logbook_begin */ 0x0440, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x0440, /* rb_profile_begin */ 0x8000, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -94,6 +98,7 @@ static const oceanic_common_layout_t oceanic_wisdom_layout = { 0x03D0, /* rb_logbook_begin */ 0x05D0, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x05D0, /* rb_profile_begin */ 0x8000, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -109,6 +114,7 @@ static const oceanic_common_layout_t aeris_500ai_layout = { 0x0200, /* rb_logbook_begin */ 0x0200, /* rb_logbook_end */ 8, /* rb_logbook_entry_size */ + 1, /* rb_logbook_direction */ 0x00200, /* rb_profile_begin */ 0x20000, /* rb_profile_end */ 0, /* pt_mode_global */ @@ -286,7 +292,49 @@ oceanic_vtpro_calibrate (oceanic_vtpro_device_t *device) } static dc_status_t -oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook) +oceanic_aeris500ai_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end) +{ + dc_status_t status = DC_STATUS_SUCCESS; + oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract; + + assert (device != NULL); + assert (device->base.layout != NULL); + assert (rb_logbook_begin != NULL && rb_logbook_end != NULL); + assert (rb_profile_begin != NULL && rb_profile_end != NULL); + + const oceanic_common_layout_t *layout = device->base.layout; + + // Read the pointer data. + unsigned char pointers[PAGESIZE] = {0}; + status = oceanic_vtpro_device_read (abstract, layout->cf_pointers, pointers, sizeof (pointers)); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to read the memory page."); + return status; + } + + // Update and emit a progress event. + if (progress) { + progress->current += PAGESIZE; + progress->maximum += PAGESIZE; + device_event_emit (abstract, DC_EVENT_PROGRESS, progress); + } + + // Get the pointers. + unsigned int rb_logbook_first = pointers[0x02]; + unsigned int rb_logbook_last = pointers[0x03]; + unsigned int rb_profile_first = array_uint16_le (pointers + 4) * PAGESIZE; + unsigned int rb_profile_last = array_uint16_le (pointers + 6) * PAGESIZE; + + *rb_logbook_begin = rb_logbook_first; + *rb_logbook_end = rb_logbook_last; + *rb_profile_begin = rb_profile_first; + *rb_profile_end = rb_profile_last; + + return status; +} + +static dc_status_t +oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end) { dc_status_t rc = DC_STATUS_SUCCESS; oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract; @@ -297,30 +345,15 @@ oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *p assert (device->base.layout->rb_logbook_begin == device->base.layout->rb_logbook_end); assert (progress != NULL); - const oceanic_common_layout_t *layout = device->base.layout; - // Erase the buffer. if (!dc_buffer_clear (logbook)) return DC_STATUS_NOMEMORY; - // Read the pointer data. - unsigned char pointers[PAGESIZE] = {0}; - rc = oceanic_vtpro_device_read (abstract, layout->cf_pointers, pointers, sizeof (pointers)); - if (rc != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to read the memory page."); - return rc; - } - - // Get the logbook pointers. - unsigned int first = pointers[0x02]; - unsigned int last = pointers[0x03]; - // Get the number of dives. - unsigned int ndives = last - first + 1; + unsigned int ndives = end - begin + 1; // Update and emit a progress event. - progress->current += PAGESIZE; - progress->maximum += PAGESIZE + ndives * PAGESIZE / 2; + progress->maximum += ndives * PAGESIZE / 2; device_event_emit (abstract, DC_EVENT_PROGRESS, progress); // Allocate memory for the logbook entries. @@ -329,8 +362,8 @@ oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *p // Send the logbook index command. unsigned char command[] = {0x52, - first & 0xFF, - last & 0xFF, + begin & 0xFF, + end & 0xFF, 0x00}; rc = oceanic_vtpro_transfer (device, command, sizeof (command), NULL, 0); if (rc != DC_STATUS_SUCCESS) { @@ -378,14 +411,26 @@ oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *p } static dc_status_t -oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook) +oceanic_vtpro_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end) { oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract; if (device->base.model == AERIS500AI) { - return oceanic_aeris500ai_device_logbook (abstract, progress, logbook); + return oceanic_aeris500ai_device_pointers (abstract, progress, rb_logbook_begin, rb_logbook_end, rb_profile_begin, rb_profile_end); } else { - return oceanic_common_device_logbook (abstract, progress, logbook); + return oceanic_common_device_pointers (abstract, progress, rb_logbook_begin, rb_logbook_end, rb_profile_begin, rb_profile_end); + } +} + +static dc_status_t +oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end) +{ + oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract; + + if (device->base.model == AERIS500AI) { + return oceanic_aeris500ai_device_logbook (abstract, progress, logbook, begin, end); + } else { + return oceanic_common_device_logbook (abstract, progress, logbook, begin, end); } }