[PATCH 3/3] Cochran: Added detection for dives with overwritten profile data.
John Van Ostrand
john at vanostrand.com
Sat Jan 23 14:36:48 PST 2016
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;
--
2.4.3
More information about the devel
mailing list