Dives are checked to ensure their profile data has not been overwritten.
Also fixed a bug where bottom time for Commanders was being reported incorrectly. --- src/cochran_cmdr_parser.c | 2 +- src/cochran_commander.c | 135 +++++++++++++++++++++++++++++++++++++++------- src/cochran_commander.h | 3 ++ 3 files changed, 120 insertions(+), 20 deletions(-)
diff --git a/src/cochran_cmdr_parser.c b/src/cochran_cmdr_parser.c index af0f112..b4e8fb7 100644 --- a/src/cochran_cmdr_parser.c +++ b/src/cochran_cmdr_parser.c @@ -56,7 +56,7 @@ cochran_cmdr_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, *((unsigned int*) value) = ((float) log[CMD_MAX_TEMP] / 2 + 20 - 32) / 1.8; case DC_FIELD_DIVETIME: - *((unsigned int *) value) = array_uint16_le (log + EMC_BT) * 60; + *((unsigned int *) value) = array_uint16_le (log + CMD_BT) * 60; break; case DC_FIELD_MAXDEPTH: *((double *) value) = (float) array_uint16_le (log + CMD_MAX_DEPTH) diff --git a/src/cochran_commander.c b/src/cochran_commander.c index 74464e2..a8b2f4a 100644 --- a/src/cochran_commander.c +++ b/src/cochran_commander.c @@ -22,7 +22,6 @@ #include <string.h> // memcpy, memcmp #include <stdlib.h> // malloc, free #include <assert.h> // assert -#include <stdio.h> // DEBUG JVO
#include <libdivecomputer/cochran.h>
@@ -39,6 +38,8 @@ rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ )
+#define MIN(a,b) ((a) < (b) ? (a) : (b)) +
/* * Hardware and data layout information for various Cochran models. @@ -56,6 +57,7 @@ static cochran_layout_t cochran_layout_cmdr = { 0x00000000, /* rb_logbook_begin */ 0x00020000, /* rb_logbook_end */ 256, /* rb_log_size */ + 512, /* rb_max_log */ 0x00020000, /* rb_profile_begin */ 0x00100000, /* rb_profile_end */
@@ -66,7 +68,7 @@ static cochran_layout_t cochran_layout_cmdr = {
0x046, /* pt_conf_dive_count */ 0x06e, /* pt_conf_last_log */ - 0x0a7, /* pt_conf_last_interdive */ + 0x071, /* pt_conf_last_interdive */ };
static cochran_layout_t cochran_layout_emc20 = { @@ -79,6 +81,7 @@ static cochran_layout_t cochran_layout_emc20 = { 0x00000000, /* rb_logbook_begin */ 0x00080000, /* rb_logbook_end */ 512, /* rb_log_size */ + 1024, /* rb_max_log */ 0x00094000, /* rb_profile_begin */ 0x01000000, /* rb_profile_end */
@@ -88,8 +91,8 @@ static cochran_layout_t cochran_layout_emc20 = { 0x100, /* pt_log_profile_end */
0x0d2, /* pt_conf_dive_count */ - 0x142, /* pt_conf_last_log */ - 0x13e, /* pt_conf_last_interdive */ + 0x13e, /* pt_conf_last_log */ + 0x142, /* pt_conf_last_interdive */ };
static cochran_layout_t cochran_layout_emc16 = { @@ -102,6 +105,7 @@ static cochran_layout_t cochran_layout_emc16 = { 0x00000000, /* rb_logbook_begin */ 0x00080000, /* rb_logbook_end */ 512, /* rb_log_size */ + 1024, /* rb_max_log */ 0x00094000, /* rb_profile_begin */ 0x00800000, /* rb_profile_end */
@@ -111,8 +115,8 @@ static cochran_layout_t cochran_layout_emc16 = { 0x100, /* pt_log_profile_end */
0x0d2, /* pt_conf_dive_count */ - 0x142, /* pt_conf_last_log */ - 0x13e, /* pt_conf_last_interdive */ + 0x13e, /* pt_conf_last_log */ + 0x142, /* pt_conf_last_interdive */ };
static cochran_layout_t cochran_layout_emc14 = { @@ -125,6 +129,7 @@ static cochran_layout_t cochran_layout_emc14 = { 0x00000000, /* rb_logbook_begin */ 0x00020000, /* rb_logbook_end */ 512, /* rb_log_size */ + 256, /* rb_max_log */ 0x00022000, /* rb_profile_begin */ 0x00200000, /* rb_profile_end */
@@ -134,8 +139,8 @@ static cochran_layout_t cochran_layout_emc14 = { 0x100, /* pt_log_profile_end */
0x0d2, /* pt_conf_dive_count */ - 0x142, /* pt_conf_last_log */ - 0x13e, /* pt_conf_last_interdive */ + 0x13e, /* pt_conf_last_log */ + 0x142, /* pt_conf_last_interdive */ };
static const dc_device_vtable_t cochran_commander_device_vtable = { @@ -155,6 +160,8 @@ cochran_read_id(dc_device_t *device); static dc_status_t cochran_commander_read (dc_device_t *abstract, dc_event_progress_t *progress, unsigned int address, unsigned char data[], unsigned int size); +static void +cochran_check_profiles(dc_device_t *abstract, cochran_layout_t *layout);
static dc_status_t @@ -753,6 +760,9 @@ cochran_commander_device_read_all (dc_device_t *abstract) if (rc != DC_STATUS_SUCCESS) return rc;
+ // Determine logs that haven't had profile data overwritten + cochran_check_profiles(abstract, layout); + return DC_STATUS_SUCCESS; }
@@ -864,7 +874,7 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_status_t rc;
unsigned char *log, *fingerprint, *sample, *dive; - unsigned int sample_size, dive_size; + int sample_size, dive_size;
rc = cochran_commander_device_read_all (abstract);
@@ -886,7 +896,12 @@ cochran_commander_device_foreach (dc_device_t *abstract, sample = data->sample + sample_start_address - data->sample_data_offset;
// Determine size of sample - sample_size = sample_end_address - sample_start_address; + unsigned int dive_num =array_uint16_le(log + layout->pt_log_dive_number); + if (dive_num >= data->profile_tail) + sample_size = sample_end_address - sample_start_address; + else + sample_size = 0; + if (sample_size < 0) // Adjust for ring buffer wrap-around sample_size += layout->rb_profile_end @@ -904,15 +919,18 @@ cochran_commander_device_foreach (dc_device_t *abstract, memcpy(dive + COCHRAN_MODEL_SIZE, log, layout->rb_log_size); // log
// Copy profile data - if (sample_start_address <= sample_end_address) { - memcpy(dive + COCHRAN_MODEL_SIZE + layout->rb_log_size, sample, - sample_size); - } else { - // It wrapped the buffer, copy two sections - unsigned int size = layout->rb_profile_end - sample_start_address; - memcpy(dive + COCHRAN_MODEL_SIZE + layout->rb_log_size, sample, size); - memcpy(dive + COCHRAN_MODEL_SIZE + layout->rb_log_size + size, - data->sample, sample_size - size); + if (sample_size) { + if (sample_start_address <= sample_end_address) { + memcpy(dive + COCHRAN_MODEL_SIZE + layout->rb_log_size, sample, + sample_size); + } else { + // It wrapped the buffer, copy two sections + unsigned int size = layout->rb_profile_end - sample_start_address; + + memcpy(dive + COCHRAN_MODEL_SIZE + layout->rb_log_size, sample, size); + memcpy(dive + COCHRAN_MODEL_SIZE + layout->rb_log_size + size, + data->sample, sample_end_address - layout->rb_profile_begin); + } }
if (callback && !callback (dive, dive_size, fingerprint, @@ -926,3 +944,82 @@ cochran_commander_device_foreach (dc_device_t *abstract,
return DC_STATUS_SUCCESS; } + + +/* +* cochran_check_profiles(dc_device_t *abstract) +* +* Scan logs to identify which have valid profile data, i.e. the profiles +* have not been overwritten in the ringbuffer. +* +*/ + +static void +cochran_check_profiles(dc_device_t *abstract, cochran_layout_t *layout) { + cochran_device_t *device = (cochran_device_t *) abstract; + + // Find head log entry + // Set handy point to first dive's dive number + unsigned char *l = device->data.logbook + layout->pt_log_dive_number; + int head; + for (head = 0; head < layout->rb_max_log - 1; head ++) { + int this_dive = array_uint16_le(l); + l += layout->rb_log_size; + int next_dive = array_uint16_le(l); + + if (next_dive < this_dive || next_dive == 0xFFFF) + break; + } + + // This is the last piece of data + unsigned int head_ptr; + if (layout->endian == ENDIAN_LE) + head_ptr = array_uint32_le(device->data.config[0] + layout->pt_conf_last_log); + else + head_ptr = array_uint32_be(device->data.config[0] + layout->pt_conf_last_log); + + // Cochran (commander at least) erases 8k blocks, so round up + head_ptr = (head_ptr & 0xfffff000) + 0x2000; + + // Now move backwards until we find a profile that overlaps this one. + // Wrap around the ring buffer if needed. + + int tail; + int profile_wrap = 0; + int n = head - 1; + if (n < 0) + n = MIN(layout->rb_max_log - 1, head); + + while (n != head) { + unsigned int start_dive_ptr = array_uint32_le(device->data.logbook + layout->rb_log_size * n + layout->pt_log_profile_begin); + unsigned int end_dive_ptr = array_uint32_le(device->data.logbook + layout->rb_log_size * n + layout->pt_log_profile_end); + + if (start_dive_ptr == 0xFFFFFFFF || start_dive_ptr == 0) { + n--; + if (n < 0) + n = MIN(layout->rb_max_log - 1, head); + continue; + } + + tail = n; + + if (profile_wrap) { + if (start_dive_ptr < head_ptr) { + // We've found the last valid dive + break; + } + } else { + if (start_dive_ptr > end_dive_ptr) + profile_wrap = 1; + } + + n--; + if (n < 0) + n = MIN(layout->rb_max_log - 1, head); + } + + device->data.log_head = head; + device->data.profile_head = head; + + device->data.profile_tail = tail; +} diff --git a/src/cochran_commander.h b/src/cochran_commander.h index f9d09ec..981750c 100644 --- a/src/cochran_commander.h +++ b/src/cochran_commander.h @@ -67,6 +67,7 @@ typedef struct cochran_layout_t { unsigned int rb_logbook_begin; unsigned int rb_logbook_end; unsigned int rb_log_size; + unsigned int rb_max_log; unsigned int rb_profile_begin; unsigned int rb_profile_end;
@@ -115,6 +116,8 @@ typedef struct cochran_data_t { unsigned short int dive_count; unsigned char fingerprint[COCHRAN_FINGERPRINT_SIZE]; int fp_dive_num; + int log_head, log_tail; // head and tail for log ringbuffer + int profile_head, profile_tail; // Entries that have valid profiles
unsigned int logbook_size;