[PATCH 1/2] Cochran: Merged logic to get for valid profiles in _foreach().

John Van Ostrand john at vanostrand.com
Tue Mar 8 11:24:07 PST 2016


Previously cochran_check_profiles() was called to establish which
dive is the earliest one with a profile. Now logic in foreach()
counts profile data to detect when dives no longer have valid
profile data.
---
 src/cochran_commander.c | 146 +++++++++++++++---------------------------------
 src/cochran_commander.h |   4 +-
 2 files changed, 46 insertions(+), 104 deletions(-)

diff --git a/src/cochran_commander.c b/src/cochran_commander.c
index 127518d..47ecebb 100644
--- a/src/cochran_commander.c
+++ b/src/cochran_commander.c
@@ -67,7 +67,7 @@ const cochran_device_info_t cochran_cmdr_device_info = {
 const cochran_conf_offsets_t cochran_cmdr_conf_offsets = {
 	0x046,		// dive_count
 	0x06e,		// last_log
-	0x071,		// last_interdive
+	0x200,		// last_interdive
 	0x0aa,		// serial_number
 };
 
@@ -202,8 +202,6 @@ cochran_read_id(dc_device_t *device, unsigned char *id, int size);
 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_data_t *data);
 
 
 static dc_status_t
@@ -599,13 +597,17 @@ cochran_read_config (dc_device_t *abstract, cochran_data_t *data, dc_event_progr
 	dc_status_t rc;
 	unsigned char command[2] = { 0x96, 0x00 };
 
-	rc = cochran_packet(device, progress, command, sizeof(command), data->config, sizeof(data->config), 0);
-	if (rc != DC_STATUS_SUCCESS)
-		return rc;
+	// Read two 512 byte blocks into one 1024 byte buffer
+	for (int i = 0; i < 2; i++) {
+		command[1] = i;
+		rc = cochran_packet(device, progress, command, sizeof(command), data->config + i * 512, sizeof(data->config) / 2, 0);
+		if (rc != DC_STATUS_SUCCESS)
+			return rc;
 
-	vendor.data = data->config;
-	vendor.size = sizeof(data->config);
-	device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
+		vendor.data = data->config + i * 512;
+		vendor.size = sizeof(data->config) / 2;
+		device_event_emit (abstract, DC_EVENT_VENDOR, &vendor);
+	}
 
 	return DC_STATUS_SUCCESS;
 }
@@ -806,9 +808,6 @@ cochran_commander_device_read_all (dc_device_t *abstract, cochran_data_t *data)
 	if (rc != DC_STATUS_SUCCESS)
 		return rc;
 
-	// Determine logs that haven't had profile data overwritten
-	cochran_check_profiles(abstract, data);
-
 	return DC_STATUS_SUCCESS;
 }
 
@@ -919,6 +918,17 @@ cochran_commander_device_foreach (dc_device_t *abstract,
 	if (rc != DC_STATUS_SUCCESS)
 		return rc;
 
+	// Calculate profile RB effective head pointer
+	// Cochran seems to erase 8K chunks so round up.
+	int last_start_address = (array_uint32_le(data.config + device->conf_ptr->last_interdive) & 0xfffff000) + 0x2000;
+	if (last_start_address < device->info->rb_profile_begin || last_start_address > device->info->rb_profile_end) {
+		ERROR(abstract->context, "Invalid profile ringbuffer head pointer in Cochra config block.");
+		return DC_STATUS_DATAFORMAT;
+	}
+
+	// We track profile ringbuffer usage to determine which dives have profile data
+	int profile_capacity_remaining = device->info->rb_profile_end - device->info->rb_profile_begin;
+
 	// Loop through each dive
 	int i;
 	for (i = data.dive_count - 1; i > data.fp_dive_num; i--) {
@@ -940,19 +950,32 @@ cochran_commander_device_foreach (dc_device_t *abstract,
 			// Corrupt dive, guess the end address
 			sample_end_address = cochran_guess_sample_end_address(device, &data, i);
 
-		sample = data.sample + sample_start_address - data.sample_data_offset;
+		// Determine if sample exists
+		if (profile_capacity_remaining > 0) {
+			// Subtract this dive's profile size including post-dive events
+			profile_capacity_remaining -= (last_start_address - sample_start_address);
+			// Adjust for a dive that wraps the buffer
+			if (sample_start_address > last_start_address)
+				profile_capacity_remaining -= device->info->rb_profile_end - device->info->rb_profile_begin;
+		}
+		last_start_address = sample_start_address;
 
-		// Determine size of sample
-		unsigned int dive_num =array_uint16_le(log_entry + device->log_ptr->dive_number);
-		if (dive_num >= data.profile_tail)
-			sample_size = sample_end_address - sample_start_address;
-		else
+		if (profile_capacity_remaining < 0) {
+			// There is no profile for this dive
+			sample = NULL;
 			sample_size = 0;
+			WARNING(abstract->context, "Profile data for dive %d was overwritten by newer dives.",
+				array_uint16_le(log_entry + device->log_ptr->dive_number));
+		} else {
+			// Calculate the size of the profile only
+			sample = data.sample + sample_start_address - data.sample_data_offset;
+			sample_size = sample_end_address - sample_start_address;
 
-		if (sample_size < 0)
-			// Adjust for ring buffer wrap-around
-			sample_size += device->info->rb_profile_end
-				- device->info->rb_profile_begin;
+			if (sample_size < 0)
+				// Adjust for ring buffer wrap-around
+				sample_size += device->info->rb_profile_end
+					- device->info->rb_profile_begin;
+		}
 
 		fingerprint = log_entry;	// Date bytes
 
@@ -990,82 +1013,3 @@ 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_data_t *data) {
-	cochran_device_t *device = (cochran_device_t *) abstract;
-
-	// Find head log entry
-	// Set handy point to first dive's dive number
-	unsigned char *l = data->logbook + device->log_ptr->dive_number;
-	int head;
-	for (head = 0; head < device->info->logbook_entry_count - 1; head ++) {
-		int this_dive = array_uint16_le(l);
-		l += device->info->logbook_entry_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 (device->info->endian == ENDIAN_LE)
-		head_ptr = array_uint32_le(data->config + device->conf_ptr->last_log);
-	else
-		head_ptr = array_uint32_be(data->config + device->conf_ptr->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(device->info->logbook_entry_count - 1, head);
-
-	while (n != head) {
-		unsigned int start_dive_ptr = array_uint32_le(data->logbook + device->info->logbook_entry_size * n + device->log_ptr->profile_begin_offset);
-		unsigned int end_dive_ptr = array_uint32_le(data->logbook + device->info->logbook_entry_size * n + device->log_ptr->profile_end_offset);
-
-		if (start_dive_ptr == 0xFFFFFFFF || start_dive_ptr == 0) {
-			n--;
-			if (n < 0)
-				n = MIN(device->info->logbook_entry_count - 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(device->info->logbook_entry_count - 1, head);
-	}
-
-	data->log_head = head;
-	data->profile_head = head;
-
-	data->profile_tail = tail;
-}
diff --git a/src/cochran_commander.h b/src/cochran_commander.h
index f6e3921..14cfedf 100644
--- a/src/cochran_commander.h
+++ b/src/cochran_commander.h
@@ -96,14 +96,12 @@ typedef struct cochran_log_offsets_t {
 } cochran_log_offsets_t;
 
 typedef struct cochran_data_t {
-	unsigned char config[512];
+	unsigned char config[1024];
 	unsigned char *logbook;
 	unsigned char *sample;
 
 	unsigned short int dive_count;
 	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