[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