[PATCH] Cochran_commander refactoring

John Van Ostrand john at vanostrand.com
Wed Nov 19 08:51:19 PST 2014


This changes the data passed back by the foreach function and the data
that is passed to the parser. It creates a structure containing everything
needed to parse the dive. Pointers were removed so that the data can be
stored and parsed later.

Fixed a typo in COCHRAN_TIMESTAMP_OFFSET.
Fixed a bug that occured in calculating NDL and Deco time if an event
occurred between samples.
Added start temperature to Commander parse.
Made corrupt dive recovery cleaner.
Cleaned up many compiler warnings (-Wall)
Cleaned up some whitespace
Re-wrapped some lines.
Removed extraneous parenthesis not needed with & operator.
Seperated device configuration from device handle (more or less)
Cleaned up sample buffer wrap-around logic and used better var naming.
Fixed typo in CMD_START_OFFSET
---
 src/cochran_cmdr_parser.c      |  66 +++++-----
 src/cochran_commander.c        | 288 ++++++++++++++++++++++++-----------------
 src/cochran_commander.h        |  59 +++++----
 src/cochran_commander_parser.c |  57 +++++---
 src/cochran_commander_parser.h |   2 +
 src/cochran_emc_parser.c       | 182 ++++++++++++--------------
 6 files changed, 353 insertions(+), 301 deletions(-)

diff --git a/src/cochran_cmdr_parser.c b/src/cochran_cmdr_parser.c
index de25912..b2b9748 100644
--- a/src/cochran_cmdr_parser.c
+++ b/src/cochran_cmdr_parser.c
@@ -35,15 +35,12 @@
 #include "cochran_commander_parser.h"
 
 
-#define SZ_SAMPLE	2
-
-
 dc_status_t
 cochran_cmdr_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
 		unsigned int flags, void *value)
 {
-	cochran_data_t *data = (cochran_data_t *) abstract->data;
-	unsigned char *log = data->current_log;
+	const unsigned char *data = abstract->data;
+	const unsigned char *log = data + COCHRAN_MODEL_SIZE;
 
 	dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
 	dc_salinity_t *water = (dc_salinity_t *) value;
@@ -53,31 +50,35 @@ cochran_cmdr_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
 		case DC_FIELD_TEMPERATURE_SURFACE:
 			*((unsigned int*) value) = ((float) log[CMD_START_TEMP] - 32) / 1.8;
 		case DC_FIELD_TEMPERATURE_MINIMUM:
-			*((unsigned int*) value) = ((float) log[CMD_MIN_TEMP] / 2 + 20 - 32) / 1.8;
+			*((unsigned int*) value) = ((float) log[CMD_MIN_TEMP] / 2
+				+ 20 - 32) / 1.8;
 		case DC_FIELD_TEMPERATURE_MAXIMUM:
-			*((unsigned int*) value) = ((float) log[CMD_MAX_TEMP] / 2 + 20 - 32) / 1.8;
+			*((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;
 			break;
 		case DC_FIELD_MAXDEPTH:
-			*((double *) value) = (float) array_uint16_le (log + CMD_MAX_DEPTH) / 4 * FEET;
+			*((double *) value) = (float) array_uint16_le (log + CMD_MAX_DEPTH)
+				/ 4 * FEET;
 			break;
 		case DC_FIELD_AVGDEPTH:
-			*((double *) value) = (float) array_uint16_le (log + CMD_AVG_DEPTH) / 4 * FEET;
+			*((double *) value) = (float) array_uint16_le (log + CMD_AVG_DEPTH)
+				/ 4 * FEET;
 			break;
 		case DC_FIELD_GASMIX_COUNT:
 			*((unsigned int *) value) = 2;
 			break;
 		case DC_FIELD_GASMIX:
-			gasmix->oxygen = (double) array_uint16_le ((char *)log
+			gasmix->oxygen = (double) array_uint16_le (log
 					+ CMD_O2_PERCENT + 2 * flags) / 256 / 100;
 			gasmix->helium = 0;
 			gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
 			break;
 		case DC_FIELD_SALINITY:
 			// 0 = low conductivity, 1 = high, maybe there's a 2?
-			water->type = ( (log[CMD_WATER_CONDUCTIVITY] & 0x3) == 0 ? DC_WATER_FRESH
-					: DC_WATER_SALT );
+			water->type = ( (log[CMD_WATER_CONDUCTIVITY] & 0x3) == 0
+				? DC_WATER_FRESH : DC_WATER_SALT );
 			water->density = 1000 + 12.5 * (log[CMD_WATER_CONDUCTIVITY] & 0x3);
 			break;
 		case DC_FIELD_ATMOSPHERIC:
@@ -97,11 +98,12 @@ dc_status_t
 cochran_cmdr_parser_samples_foreach (dc_parser_t *abstract,
 		dc_sample_callback_t callback, void *userdata)
 {
-	cochran_data_t *data = (cochran_data_t *)abstract->data;
-	unsigned char *sdata = data->current_sample;
-	unsigned char *log = data->current_log;
-	unsigned int size = data->current_sample_size;
-	unsigned char *s;
+	const unsigned char *log = abstract->data + COCHRAN_MODEL_SIZE;
+	const unsigned char *samples = log + COCHRAN_CMDR_LOG_SIZE;
+
+	unsigned int size = abstract->size - COCHRAN_MODEL_SIZE
+		- COCHRAN_CMDR_LOG_SIZE;
+	const unsigned char *s;
 
 	dc_sample_value_t sample = {0}, empty_sample = {0};
 	unsigned int time = 0, last_sample_time;
@@ -109,8 +111,10 @@ cochran_cmdr_parser_samples_foreach (dc_parser_t *abstract,
 	double temperature;
 	double depth;
 	double ascent_rate;
-	unsigned char deco_obligation = 0;
-	unsigned int deco_time = 0;
+	unsigned char corrupt_dive = 0;
+
+	if (array_uint32_le(log + COCHRAN_CMDR_LOG_SIZE / 2) == 0xFFFFFFFF)
+		corrupt_dive = 1;
 
 	// Cochran samples depth every second and varies between ascent rate
 	// and temp ever other second.
@@ -124,8 +128,8 @@ cochran_cmdr_parser_samples_foreach (dc_parser_t *abstract,
 	sample.depth = depth * FEET;
 	if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata);
 
-	// TODO: sample.temperature = (log + CMD_START_TEMP - 32) / 1.8;
-	// TODO: if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
+	sample.temperature = (float) *(log + CMD_START_TEMP) - 32 / 1.8;
+	if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
 
 	while (offset < size) {
 		sample = empty_sample;
@@ -137,13 +141,10 @@ cochran_cmdr_parser_samples_foreach (dc_parser_t *abstract,
 			callback (DC_SAMPLE_TIME, sample, userdata);
 		}
 
-		if (offset > data->sample_memory_end_address)
-			s = sdata + offset - data->sample_memory_end_address - 1;
-		else
-			s = sdata + offset;
+		s = samples + offset;
 
 		// If corrupt_dive end before offset
-		if (data->corrupt_dive) {
+		if (corrupt_dive) {
 			if (   s[0] == 0x10
 				|| s[0] == 0xFF
 				|| s[0] == 0xA8) {
@@ -155,17 +156,12 @@ cochran_cmdr_parser_samples_foreach (dc_parser_t *abstract,
 
 		// Check for event
 		if (s[0] & 0x80) {
-			offset += cochran_commander_handle_event(abstract, callback, userdata,
-					s[0], offset, time);
-			if (s[0] == 0xC5)
-				deco_obligation = 1;	// Deco obligation begins
-			else if (s[0] == 0xC8) 
-				deco_obligation = 0;	// Deco obligation ends
-
+			offset += cochran_commander_handle_event(abstract, callback,
+				userdata, s[0], offset, time);
 			continue;
 		}
 
-			
+
 		// Depth is logged as change in feet, bit 0x40 means negative depth
 		depth += (float) (s[0] & 0x3F) / 4 * (s[0] & 0x40 ? -1 : 1);
 		sample.depth = depth * FEET;
@@ -186,7 +182,7 @@ cochran_cmdr_parser_samples_foreach (dc_parser_t *abstract,
 		}
 
 		time ++;
-		offset += SZ_SAMPLE;
+		offset += COCHRAN_CMDR_SAMPLE_SIZE;
 	}
 
 	return DC_STATUS_SUCCESS;
diff --git a/src/cochran_commander.c b/src/cochran_commander.c
index e8884c1..fdcac67 100644
--- a/src/cochran_commander.c
+++ b/src/cochran_commander.c
@@ -42,13 +42,17 @@ static const dc_device_vtable_t cochran_commander_device_vtable = {
 	DC_FAMILY_COCHRAN_COMMANDER,
 	cochran_commander_device_set_fingerprint,	/* set_fingerprint */
 	cochran_commander_device_read,				/* read */
-	NULL,									/* write */
+	NULL,										/* write */
 	cochran_commander_device_dump,				/* dump */
 	cochran_commander_device_foreach,			/* foreach */
 	cochran_commander_device_close				/* close */
 };
 
 
+static dc_status_t
+cochran_read_id(dc_device_t *device);
+
+
 dc_status_t
 cochran_packet (cochran_device_t *device, const unsigned char command[],
 		unsigned int csize, unsigned char answer[], unsigned int asize,
@@ -76,9 +80,9 @@ cochran_packet (cochran_device_t *device, const unsigned char command[],
 
 		// Weird but I only get the right result when I do it twice
 		// Rates are odd, like 825600 for the EMC, 115200 for commander
-		serial_configure(device->port, device->data.high_baud, 8,
+		serial_configure(device->port, device->data.conf.high_baud, 8,
 						SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE);
-		serial_configure(device->port, device->data.high_baud, 8,
+		serial_configure(device->port, device->data.conf.high_baud, 8,
 						SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE);
 	}
 
@@ -202,7 +206,8 @@ cochran_commander_device_open (dc_device_t **out, dc_context_t *context,
 	device->progress = NULL;
 	device->data.logbook = NULL;
 	device->data.sample = NULL;
-	cochran_commander_device_set_fingerprint((dc_device_t *) device, "", 0);
+	cochran_commander_device_set_fingerprint((dc_device_t *) device,
+		NULL, 0);
 
 	rc = cochran_commander_serial_open(device, context);
 	if (rc != DC_STATUS_SUCCESS)
@@ -219,8 +224,13 @@ cochran_commander_device_open (dc_device_t **out, dc_context_t *context,
 	}
 
 	// Check ID
-	if ((device->data.model & 0xFF0000) == COCHRAN_MODEL_UNKNOWN) {
-		ERROR (context, "Device not recognized.");
+	if ((device->data.conf.model & 0xFF0000) == COCHRAN_MODEL_UNKNOWN) {
+		ERROR (context,
+			"Unknown Cochran model %02x %02x %02x %02x %02x %02x %02x %02x",
+			*(device->data.id + 0x3B),     *(device->data.id + 0x3B + 1),
+			*(device->data.id + 0x3B + 2), *(device->data.id + 0x3B + 3),
+			*(device->data.id + 0x3B + 4), *(device->data.id + 0x3B + 5),
+			*(device->data.id + 0x3B + 6), *(device->data.id + 0x3B + 7));
 		serial_close (device->port);
 		free (device);
 		return DC_STATUS_UNSUPPORTED;
@@ -257,15 +267,15 @@ cochran_commander_device_set_fingerprint (dc_device_t *abstract,
 		const unsigned char data[], unsigned int size)
 {
 	cochran_device_t *device = (cochran_device_t *) abstract;
-	cochran_data_t *d = &(device->data);
+	cochran_data_t *d = &device->data;
 
 	if (size && size != sizeof (d->fingerprint))
 		return DC_STATUS_INVALIDARGS;
 
 	if (size)
-		memcpy (&(d->fingerprint), data, sizeof (d->fingerprint));
+		memcpy (&d->fingerprint, data, sizeof (d->fingerprint));
 	else
-		memset (&(d->fingerprint), 0xFF, sizeof (d->fingerprint));
+		memset (&d->fingerprint, 0xFF, sizeof (d->fingerprint));
 
 	return DC_STATUS_SUCCESS;
 }
@@ -281,7 +291,7 @@ cochran_commander_device_read (dc_device_t *abstract, unsigned int address,
 	unsigned char command[10];
 	unsigned char command_size;
 
-	switch (device->data.address_length)
+	switch (device->data.conf.address_length)
 	{
 	case COCHRAN_ADDRESS_LENGTH_32:
 		// EMC uses 32 bit addressing
@@ -322,71 +332,65 @@ cochran_commander_device_read (dc_device_t *abstract, unsigned int address,
 }
 
 
-static void
-cochran_set_device_config (cochran_device_t *device)
+void
+cochran_commander_get_config (const unsigned char *model,
+		cochran_config_t *conf)
 {
-	dc_device_t *abstract = (dc_device_t *) device;
 	// Determine model
-	if (memcmp(device->data.id + 0x3B, "AM2315\xA3\x71", 8) == 0)
+	if (memcmp(model, "AM2315\xA3\x71", 8) == 0)
 	{
-		device->data.model = COCHRAN_MODEL_EMC_20;
-		device->data.log_size = 512;
-		device->data.sample_memory_start_address = 0x94000;
-		device->data.dive_num_ptr = 0x56;
-		device->data.dive_count_ptr = 0xD2;
-		device->data.dive_count_endian = COCHRAN_LE_TYPE;
-		device->data.sample_end_ptr = 256;
-		device->data.log_pre_dive_ptr = 30;
-		device->data.log_end_dive_ptr = 256;
-		device->data.last_interdive_ptr = 233;
-		device->data.last_entry_ptr = 194;
-		device->data.date_format = COCHRAN_DATE_FORMAT_SMHDMY;
-		device->data.address_length = COCHRAN_ADDRESS_LENGTH_32;
-		device->data.high_baud = 825600;
-	}
-	else if (memcmp(device->data.id + 0x3B, "AMA315\xC3\xC5", 8) == 0)
+		conf->model = COCHRAN_MODEL_EMC_20;
+		conf->log_size = 512;
+		conf->sample_memory_start_address = 0x94000;
+		conf->dive_num_ptr = 0x56;
+		conf->dive_count_ptr = 0xD2;
+		conf->dive_count_endian = COCHRAN_LE_TYPE;
+		conf->sample_end_ptr = 256;
+		conf->log_pre_dive_ptr = 30;
+		conf->log_end_dive_ptr = 256;
+		conf->last_interdive_ptr = 233;
+		conf->last_entry_ptr = 194;
+		conf->date_format = COCHRAN_DATE_FORMAT_SMHDMY;
+		conf->address_length = COCHRAN_ADDRESS_LENGTH_32;
+		conf->high_baud = 825600;
+	}
+	else if (memcmp(model, "AMA315\xC3\xC5", 8) == 0)
 	{
-		device->data.model = COCHRAN_MODEL_EMC_16;
-		device->data.log_size = 512;
-		device->data.sample_memory_start_address = 0x94000;
-		device->data.dive_num_ptr = 0x56;
-		device->data.dive_count_ptr = 0xD2;
-		device->data.dive_count_endian = COCHRAN_LE_TYPE;
-		device->data.sample_end_ptr = 256;
-		device->data.log_pre_dive_ptr = 30;
-		device->data.log_end_dive_ptr = 256;
-		device->data.last_interdive_ptr = 233;
-		device->data.last_entry_ptr = 194;
-		device->data.date_format = COCHRAN_DATE_FORMAT_SMHDMY;
-		device->data.address_length = COCHRAN_ADDRESS_LENGTH_32;
-		device->data.high_baud = 825600;
-	}
-	else if (memcmp(device->data.id + 0x3B, "AM\x11""2212\x02", 8) == 0)
+		conf->model = COCHRAN_MODEL_EMC_16;
+		conf->log_size = 512;
+		conf->sample_memory_start_address = 0x94000;
+		conf->dive_num_ptr = 0x56;
+		conf->dive_count_ptr = 0xD2;
+		conf->dive_count_endian = COCHRAN_LE_TYPE;
+		conf->sample_end_ptr = 256;
+		conf->log_pre_dive_ptr = 30;
+		conf->log_end_dive_ptr = 256;
+		conf->last_interdive_ptr = 233;
+		conf->last_entry_ptr = 194;
+		conf->date_format = COCHRAN_DATE_FORMAT_SMHDMY;
+		conf->address_length = COCHRAN_ADDRESS_LENGTH_32;
+		conf->high_baud = 825600;
+	}
+	else if (memcmp(model, "AM\x11""2212\x02", 8) == 0)
 	{
-		device->data.model = COCHRAN_MODEL_COMMANDER_AIR_NITROX;
-		device->data.log_size = 256;
-		device->data.sample_memory_start_address = 0x20000;
-		device->data.dive_num_ptr = 0x46;
-		device->data.dive_count_ptr = 0x46;
-		device->data.dive_count_endian = COCHRAN_BE_TYPE;
-		device->data.sample_end_ptr = 256;
-		device->data.log_pre_dive_ptr = 30;
-		device->data.log_end_dive_ptr = 128;
-		device->data.last_interdive_ptr = 167;
-		device->data.last_entry_ptr = -1;
-		device->data.date_format = COCHRAN_DATE_FORMAT_MSDHYM;
-		device->data.address_length = COCHRAN_ADDRESS_LENGTH_24;
-		device->data.high_baud = 115200;
+		conf->model = COCHRAN_MODEL_COMMANDER_AIR_NITROX;
+		conf->log_size = 256;
+		conf->sample_memory_start_address = 0x20000;
+		conf->dive_num_ptr = 0x46;
+		conf->dive_count_ptr = 0x46;
+		conf->dive_count_endian = COCHRAN_BE_TYPE;
+		conf->sample_end_ptr = 256;
+		conf->log_pre_dive_ptr = 30;
+		conf->log_end_dive_ptr = 128;
+		conf->last_interdive_ptr = 167;
+		conf->last_entry_ptr = -1;
+		conf->date_format = COCHRAN_DATE_FORMAT_MSDHYM;
+		conf->address_length = COCHRAN_ADDRESS_LENGTH_24;
+		conf->high_baud = 115200;
 	}
 	else
 	{
-		device->data.model = 0;
-		ERROR (abstract->context,
-			"Unknown Cochran model %02x %02x %02x %02x %02x %02x %02x %02x",
-			*(device->data.id + 0x3B),     *(device->data.id + 0x3B + 1),
-			*(device->data.id + 0x3B + 2), *(device->data.id + 0x3B + 3),
-			*(device->data.id + 0x3B + 4), *(device->data.id + 0x3B + 5),
-			*(device->data.id + 0x3B + 6), *(device->data.id + 0x3B + 7));
+		conf->model = 0;
 	}
 
 	return;
@@ -404,7 +408,7 @@ cochran_read_id (dc_device_t *abstract)
 	if (rc != DC_STATUS_SUCCESS)
 		return rc;
 
-	if (strncmp(device->data.id, "(C)", 3) != 0) {
+	if (strncmp((const char *)device->data.id, "(C)", 3) != 0) {
 		// It's a Commander, read again
 		memcpy(device->data.id0, device->data.id, 67);
 
@@ -416,7 +420,8 @@ cochran_read_id (dc_device_t *abstract)
 			return rc;
 	}
 
-	cochran_set_device_config(device);
+	cochran_commander_get_config(device->data.id + 0x3B, &device->data.conf);
+
 
 	return DC_STATUS_SUCCESS;
 }
@@ -427,10 +432,11 @@ cochran_read_config (dc_device_t *abstract)
 {
 	cochran_device_t *device = (cochran_device_t *) abstract;
 	cochran_data_t *data = &device->data;
+
 	dc_status_t rc;
 	unsigned char command[2] = { 0x96, 0x00 };
 
-	if ((data->model & 0xFF0000) == COCHRAN_MODEL_EMC_FAMILY)
+	if ((data->conf.model & 0xFF0000) == COCHRAN_MODEL_EMC_FAMILY)
 		data->config_count = 2;
 	else
 		data->config_count = 4;
@@ -454,7 +460,7 @@ cochran_read_misc (dc_device_t *abstract)
 
 	unsigned char command[7] = { 0x89, 0x05, 0x00, 0x00, 0x00, 0xDC, 0x05 };
 
-	switch (device->data.model & 0xFF0000)
+	switch (device->data.conf.model & 0xFF0000)
 	{
 	case COCHRAN_MODEL_COMMANDER_FAMILY:
 		command[2] = 0xCA;
@@ -486,7 +492,7 @@ static dc_status_t
 cochran_read_logbook (dc_device_t *abstract)
 {
 	cochran_device_t *device = (cochran_device_t *) abstract;
-	cochran_data_t *d = &(device->data);
+	cochran_data_t *d = &device->data;
 	dc_status_t rc;
 
 	if (d->logbook)
@@ -516,7 +522,8 @@ cochran_read_logbook (dc_device_t *abstract)
 	cochran_commander_serial_setup(device, abstract->context);
 
 	// Request log book
-	rc = cochran_commander_device_read(abstract, 0, d->logbook, d->logbook_size);
+	rc = cochran_commander_device_read(abstract, 0, d->logbook,
+		d->logbook_size);
 
 	device->progress->current = d->logbook_size;
 	device_event_emit (abstract, DC_EVENT_PROGRESS, device->progress);
@@ -530,14 +537,15 @@ static void
 cochran_find_fingerprint(dc_device_t *abstract)
 {
 	cochran_device_t *device = (cochran_device_t *) abstract;
-	cochran_data_t *d = (cochran_data_t *) &(device->data);
+	cochran_data_t *d = (cochran_data_t *) &device->data;
+	cochran_config_t *conf = &d->conf;
 
 	// Skip to fingerprint to reduce time
 	d->fp_dive_num = d->dive_count - 1;
 
-	while (d->fp_dive_num >= 0 && memcmp(&(d->fingerprint),
-						 d->logbook + d->fp_dive_num * d->log_size
-						+ d->dive_num_ptr,
+	while (d->fp_dive_num >= 0 && memcmp(&d->fingerprint,
+						 d->logbook + d->fp_dive_num * conf->log_size
+						+ conf->dive_num_ptr,
 						 sizeof(d->fingerprint)))
 		d->fp_dive_num--;
 }
@@ -547,8 +555,9 @@ static void
 cochran_get_sample_parms(dc_device_t *abstract)
 {
 	cochran_device_t *device = (cochran_device_t *) abstract;
-	cochran_data_t *d = (cochran_data_t *) &(device->data);
-	unsigned int pre_dive_offset, end_dive_offset;
+	cochran_data_t *d = (cochran_data_t *) &device->data;
+	cochran_config_t *conf = &d->conf;
+	unsigned int pre_dive_offset = 0, end_dive_offset = 0;
 	unsigned int low_offset, high_offset;
 
 	// Find lowest and highest offsets into sample data
@@ -557,10 +566,10 @@ cochran_get_sample_parms(dc_device_t *abstract)
 
 	int i;
 	for (i = d->fp_dive_num + 1; i < d->dive_count; i++) {
-		pre_dive_offset = array_uint32_le (&(d->logbook[i * d->log_size
-				+ d->log_pre_dive_ptr]));
-		end_dive_offset = array_uint32_le (&(d->logbook[i * d->log_size
-				+ d->log_end_dive_ptr]));
+		pre_dive_offset = array_uint32_le (&(d->logbook[i * conf->log_size
+				+ conf->log_pre_dive_ptr]));
+		end_dive_offset = array_uint32_le (&(d->logbook[i * conf->log_size
+				+ conf->log_end_dive_ptr]));
 
 		// Check for ring buffer wrap-around.
 		if (pre_dive_offset > end_dive_offset)
@@ -577,8 +586,8 @@ cochran_get_sample_parms(dc_device_t *abstract)
 		// I'll round to 128K, dives longer than 12 hrs aren't likely
 		// and memory in sizes not rounded to 128K might be odd.
 		high_offset = ((pre_dive_offset - 1) & 0xE0000) + 0x20000;
-		d->sample_memory_end_address = high_offset;
-		low_offset = d->sample_memory_start_address;
+		conf->sample_memory_end_address = high_offset;
+		low_offset = conf->sample_memory_start_address;
 		d->sample_data_offset = low_offset;
 		d->sample_size = high_offset - low_offset;
 	} else if (low_offset < 0xFFFFFFFF && high_offset > 0) {
@@ -597,7 +606,7 @@ static dc_status_t
 cochran_read_samples(dc_device_t *abstract)
 {
 	cochran_device_t *device = (cochran_device_t *) abstract;
-	cochran_data_t *d = (cochran_data_t *) &(device->data);
+	cochran_data_t *d = (cochran_data_t *) &device->data;
 	dc_status_t rc;
 
 
@@ -649,7 +658,8 @@ static dc_status_t
 cochran_commander_device_read_all (dc_device_t *abstract)
 {
 	cochran_device_t *device = (cochran_device_t *) abstract;
-	cochran_data_t *d = (cochran_data_t *) &(device->data);
+	cochran_data_t *d = (cochran_data_t *) &device->data;
+	cochran_config_t *conf = &d->conf;
 
 	dc_status_t rc;
 
@@ -663,12 +673,12 @@ cochran_commander_device_read_all (dc_device_t *abstract)
 		return rc;
 
 	// Determine size of dive list to read. Round up to nearest 16K
-	if (d->dive_count_endian == COCHRAN_LE_TYPE)
-		d->dive_count = array_uint16_le (d->config[0] + d->dive_count_ptr);
+	if (conf->dive_count_endian == COCHRAN_LE_TYPE)
+		d->dive_count = array_uint16_le (d->config[0] + conf->dive_count_ptr);
 	else 
-		d->dive_count = array_uint16_be (d->config[0] + d->dive_count_ptr);
+		d->dive_count = array_uint16_be (d->config[0] + conf->dive_count_ptr);
 	
-	d->logbook_size = ((d->dive_count * d->log_size) & 0xFFFFC000)
+	d->logbook_size = ((d->dive_count * conf->log_size) & 0xFFFFC000)
 		 + 0x4000;
 
 	rc = cochran_read_logbook(abstract);
@@ -696,11 +706,11 @@ dc_status_t
 cochran_commander_device_dump (dc_device_t *abstract, dc_buffer_t *data)
 {
 	cochran_device_t *device = (cochran_device_t *) abstract;
-	cochran_data_t *d = (cochran_data_t *) &(device->data);
+	cochran_data_t *d = (cochran_data_t *) &device->data;
 	int ptr = 0;
 
 	dc_status_t rc;
-	char *b;
+	unsigned char *b;
 	int size;
 
 	rc = cochran_commander_device_read_all (abstract);
@@ -816,16 +826,42 @@ cochran_commander_device_dump (dc_device_t *abstract, dc_buffer_t *data)
 }
 
 
+/*
+*  For corrupt dives the end-of-samples pointer is 0xFFFFFFFF
+*  search for a reasonable size, e.g. using next dive start sample
+*  or end-of-samples to limit searching for recoverable samples
+*/
+
+static unsigned int
+cochran_guess_sample_end_address(cochran_data_t *data, unsigned int log_num)
+{
+	cochran_config_t *conf = &data->conf;
+	const unsigned char *log = data->logbook + data->conf.log_size * log_num;
+
+	if (log_num == data->dive_count)
+		// Return next usable address from config0 page
+		return array_uint32_le(data->config[0]
+			+ conf->sample_memory_end_address);
+
+	// Next log's start address
+	return array_uint32_le(log + conf->log_size + 6);
+}
+
 
 dc_status_t
 cochran_commander_device_foreach (dc_device_t *abstract,
 		dc_dive_callback_t callback, void *userdata)
 {
 	cochran_device_t *device = (cochran_device_t *) abstract;
-	cochran_data_t *d = &(device->data);
-	unsigned int sample_start_offset, sample_end_offset;
+	cochran_data_t *data = &device->data;
+	cochran_config_t *conf = &data->conf;
+
+	unsigned int sample_start_address, sample_end_address;
 	dc_status_t rc;
 
+	unsigned char *log, *fingerprint, *sample, *dive;
+	int sample_size, dive_size;
+
 	rc = cochran_commander_device_read_all (abstract);
 
 	if (rc != DC_STATUS_SUCCESS)
@@ -833,36 +869,54 @@ cochran_commander_device_foreach (dc_device_t *abstract,
 
 	// Loop through each dive
 	int i;
-	for (i = d->dive_count - 1; i > d->fp_dive_num; i--) {
+	for (i = data->dive_count - 1; i > data->fp_dive_num; i--) {
+		log = data->logbook + i * conf->log_size;
 
-		d->current_log = d->logbook + i * d->log_size;
+		sample_start_address = array_uint32_le (log + 6);
+		sample_end_address = array_uint32_le (log + conf->log_size / 2);
 
-		sample_start_offset = array_uint32_le (d->current_log + 6);
-		sample_end_offset = array_uint32_le (d->current_log
-				+ d->log_size/2);
+		if (sample_end_address == 0xFFFFFFFF)
+			// Corrupt dive, guess the end address
+			sample_end_address = cochran_guess_sample_end_address(data, i);
 
-		d->current_sample = d->sample + sample_start_offset
-				- d->sample_data_offset;
+		sample = data->sample + sample_start_address - data->sample_data_offset;
 
-		// Check for corrupt post-dive section
-		if (array_uint32_le(d->current_log + d->log_size/2) == 0xFFFFFFFF)
-			d->corrupt_dive = 1;
-		else
-			d->corrupt_dive = 0;
+		// Determine size of sample
+		sample_size = sample_end_address - sample_start_address;
+		if (sample_size < 0)
+			// Adjust for ring buffer wrap-around
+			sample_size += conf->sample_memory_end_address
+				- conf->sample_memory_start_address;
 
-		// Check for ring buffer wrap
-		if (sample_start_offset > sample_end_offset)
-			d->current_sample_size = d->sample_memory_end_address
-				- sample_start_offset + 1 + sample_end_offset
-				- d->sample_memory_start_address + 1;
-		else
-			d->current_sample_size = sample_end_offset - sample_start_offset;
+		fingerprint = log + conf->dive_num_ptr;
+
+		// Build dive blob
+		dive_size = COCHRAN_MODEL_SIZE + conf->log_size + sample_size;
+		dive = malloc(dive_size);
+		if (dive == NULL)
+			return DC_STATUS_NOMEMORY;
 
-		d->current_fingerprint = d->current_log + d->dive_num_ptr;
+		memcpy(dive, data->id + 0x3B, 8);	// model string
+		memcpy(dive + COCHRAN_MODEL_SIZE, log, conf->log_size);
+		if (sample_start_address <= sample_end_address) {
+			memcpy(dive + COCHRAN_MODEL_SIZE + conf->log_size, sample,
+				sample_size);
+		} else {
+			// It wrapped the buffer, copy two sections
+			unsigned int size = conf->sample_memory_end_address
+				- sample_start_address;
+			memcpy(dive + COCHRAN_MODEL_SIZE + conf->log_size, sample, size);
+			memcpy(dive + COCHRAN_MODEL_SIZE + conf->log_size + size,
+				data->sample, sample_size - size);
+		}
 
-		if (callback && !callback ((unsigned char *) d, sizeof(device->data),
-				d->current_fingerprint, sizeof (d->fingerprint), userdata))
+		if (callback && !callback ((unsigned char *) dive, dive_size,
+				fingerprint, COCHRAN_FINGERPRINT_SIZE, userdata)) {
+			free(dive);
 			return DC_STATUS_SUCCESS;
+		}
+
+		free(dive);
 	}
 
 	return DC_STATUS_SUCCESS;
diff --git a/src/cochran_commander.h b/src/cochran_commander.h
index e259977..8fa6228 100644
--- a/src/cochran_commander.h
+++ b/src/cochran_commander.h
@@ -21,7 +21,16 @@
 
 // seconds to add to Cochran time stamps to get unix time
 // Equivalent to Jan 1, 1992 00:00:00
-#define COCHRAN_TIMESTAMP_OFFSET 694224000
+#define COCHRAN_TIMESTAMP_OFFSET	694242000
+
+#define COCHRAN_MODEL_SIZE			8
+#define COCHRAN_FINGERPRINT_SIZE	2
+
+#define COCHRAN_EMC_LOG_SIZE		512
+#define COCHRAN_EMC_SAMPLE_SIZE		3
+
+#define COCHRAN_CMDR_LOG_SIZE		256
+#define COCHRAN_CMDR_SAMPLE_SIZE	2
 
 #define COCHRAN_LE_TYPE 0
 #define COCHRAN_BE_TYPE 1
@@ -42,9 +51,26 @@ typedef enum cochran_model_t {
 	COCHRAN_MODEL_COMMANDER_AIR_NITROX,
 } cochran_model_t;
 
-typedef struct cochran_data_t {
+// Device configuration items
+typedef struct cochran_config_t {
 	cochran_model_t model;
+	int log_size;
+	int sample_memory_start_address;
+	int sample_memory_end_address;
+	int dive_num_ptr;
+	int dive_count_ptr;
+	int dive_count_endian;
+	int sample_end_ptr;
+	int log_pre_dive_ptr;
+	int log_end_dive_ptr;
+	int last_interdive_ptr;
+	int last_entry_ptr;
+	int date_format;
+	int address_length;
+	int high_baud; 			// baud rate to switch to for log/sample download
+} cochran_config_t;
 
+typedef struct cochran_data_t {
 	unsigned char id0[67];
 	unsigned char id[67];
 	unsigned char config[4][512];
@@ -56,38 +82,17 @@ typedef struct cochran_data_t {
 	unsigned int config_count;
 
 	unsigned short int dive_count;
-	unsigned char fingerprint[2];
+	unsigned char fingerprint[COCHRAN_FINGERPRINT_SIZE];
 	int fp_dive_num;
 
 	unsigned int logbook_size;
-	unsigned int current_sample_size;
 
 	unsigned int sample_data_offset;
 	unsigned int sample_size;
 	unsigned int last_interdive_offset;
 	unsigned int last_entry_offset;
 
-	unsigned char *current_fingerprint;
-	unsigned char *current_log;
-	unsigned char *current_sample;
-
-	// Config items
-	int log_size;
-	int sample_memory_start_address;
-	int sample_memory_end_address;
-	int dive_num_ptr;
-	int dive_count_ptr;
-	int dive_count_endian;
-	int sample_end_ptr;
-	int log_pre_dive_ptr;
-	int log_end_dive_ptr;
-	int last_interdive_ptr;
-	int last_entry_ptr;
-	int date_format;
-	int address_length;
-	int high_baud; 			// baud rate to switch to for log/sample download
-
-	unsigned char corrupt_dive;
+	cochran_config_t conf;
 } cochran_data_t;
 
 typedef struct cochran_device_t {
@@ -106,7 +111,7 @@ typedef struct cochran_device_t {
 #define CMD_DAY					  2
 #define CMD_MON					  5
 #define CMD_YEAR				  4
-#define CME_START_OFFSET		  6		// 4 bytes
+#define CMD_START_OFFSET		  6		// 4 bytes
 #define CMD_WATER_CONDUCTIVITY	 24		// 1 byte, 0=low, 2=high
 #define CMD_START_TEMP			 45		// 1 byte, F
 #define CMD_START_DEPTH			 56		// 2 byte, /4=ft
@@ -153,8 +158,8 @@ dc_status_t cochran_commander_device_set_fingerprint (dc_device_t *abstract,
 		const unsigned char data[], unsigned int size);
 dc_status_t cochran_commander_device_read (dc_device_t *abstract,
 		unsigned int address, unsigned char data[], unsigned int size);
-static dc_status_t cochran_read_id (dc_device_t *abstract);
 dc_status_t cochran_commander_device_foreach (dc_device_t *abstract,
 		dc_dive_callback_t callback, void *userdata);
 dc_status_t cochran_commander_device_dump (dc_device_t *abstract,
 		dc_buffer_t *data);
+void cochran_commander_get_config(const unsigned char *model, cochran_config_t *conf);
diff --git a/src/cochran_commander_parser.c b/src/cochran_commander_parser.c
index 547dad4..8db87cf 100644
--- a/src/cochran_commander_parser.c
+++ b/src/cochran_commander_parser.c
@@ -107,10 +107,13 @@ dc_status_t
 cochran_commander_parser_get_datetime (dc_parser_t *abstract,
 		dc_datetime_t *datetime)
 {
-	cochran_data_t *data = (cochran_data_t *) abstract->data;
-	const unsigned char *log = data->current_log;
+	const unsigned char *data = abstract->data;
+	const unsigned char *log = data + COCHRAN_MODEL_SIZE;
+	cochran_config_t conf;
 
-	if (data->date_format == COCHRAN_DATE_FORMAT_SMHDMY) {
+	cochran_commander_get_config(data, &conf);
+
+	if (conf.date_format == COCHRAN_DATE_FORMAT_SMHDMY) {
 		datetime->second = log[0];
 		datetime->minute = log[1];
 		datetime->hour = log[2];
@@ -133,9 +136,11 @@ static dc_status_t
 cochran_commander_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
 			unsigned int flags, void *value)
 {
-	cochran_data_t *data = (cochran_data_t *) abstract->data;
+	cochran_config_t conf;
+
+	cochran_commander_get_config(abstract->data, &conf);
 
-	switch (data->model & 0xFF0000)
+	switch (conf.model & 0xFF0000)
 	{
 	case COCHRAN_MODEL_COMMANDER_FAMILY:
 		return cochran_cmdr_parser_get_field(abstract, type, flags, value);
@@ -144,15 +149,19 @@ cochran_commander_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
 		return cochran_emc_parser_get_field(abstract, type, flags, value);
 		break;
 	}
+
+	return DC_STATUS_UNSUPPORTED;
 }
 
 static dc_status_t
 cochran_commander_parser_samples_foreach (dc_parser_t *abstract,
 			dc_sample_callback_t callback, void *userdata)
 {
-	cochran_data_t *data = (cochran_data_t *) abstract->data;
+	cochran_config_t conf;
 
-	switch (data->model & 0xFF0000)
+	cochran_commander_get_config(abstract->data, &conf);
+
+	switch (conf.model & 0xFF0000)
 	{
 	case COCHRAN_MODEL_COMMANDER_FAMILY:
 		return cochran_cmdr_parser_samples_foreach(abstract, callback,
@@ -163,29 +172,37 @@ cochran_commander_parser_samples_foreach (dc_parser_t *abstract,
 				userdata);
 		break;
 	}
+
+	return DC_STATUS_UNSUPPORTED;
 }
 
+void
+cochran_commander_get_event_info(const unsigned char code,
+		cochran_events_t *event)
+{
+	cochran_events_t *events = cochran_events;
+	unsigned char i = 0;
+
+	while (events[i].code && events[i].code != code)
+		i++;
 
+	*event = events[i];
+}
 
 int
 cochran_commander_handle_event (dc_parser_t *abstract,
 		dc_sample_callback_t callback, void *userdata, unsigned char code,
 		unsigned int offset, unsigned int time)
 {
-	cochran_data_t *data = (cochran_data_t *) abstract->data;
-	cochran_events_t *e = cochran_events;
-
 	dc_sample_value_t sample = {0};
+	cochran_events_t event;
 
-	unsigned char event_ptr = 0;
-
-	while (e[event_ptr].code && e[event_ptr].code != code)
-		event_ptr++;
+	cochran_commander_get_event_info(code, &event);
 
 	sample.event.time = 0;
 
-	if (e[event_ptr].code) {
-		switch (e[event_ptr].code)
+	if (event.code) {
+		switch (code)
 		{
 		case 0xAB:	// Ceiling decrease
 			// Indicated to lower ceiling by 10 ft (deeper)
@@ -199,9 +216,9 @@ cochran_commander_handle_event (dc_parser_t *abstract,
 			break;
 		default:
 			// Don't send known events of type NONE
-			if (! e[event_ptr].type == SAMPLE_EVENT_NONE) {
-				sample.event.type = e[event_ptr].type;
-				sample.event.flags = e[event_ptr].flag;
+			if (! event.type == SAMPLE_EVENT_NONE) {
+				sample.event.type = event.type;
+				sample.event.flags = event.flag;
 				if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
 			}
 		}
@@ -213,5 +230,5 @@ cochran_commander_handle_event (dc_parser_t *abstract,
 		if (callback) callback (DC_SAMPLE_EVENT, sample, userdata);
 	}
 
-	return e[event_ptr].data_bytes;
+	return event.data_bytes;
 }
diff --git a/src/cochran_commander_parser.h b/src/cochran_commander_parser.h
index 314d538..44340b5 100644
--- a/src/cochran_commander_parser.h
+++ b/src/cochran_commander_parser.h
@@ -97,6 +97,8 @@ dc_status_t cochran_commander_parser_set_data (dc_parser_t *abstract,
 		const unsigned char *data, unsigned int size);
 dc_status_t cochran_commander_parser_get_datetime (dc_parser_t *abstract,
 		dc_datetime_t *datetime);
+void cochran_commander_get_event_info(const unsigned char code,
+		cochran_events_t *event);
 int cochran_commander_handle_event (dc_parser_t *abstract,
 		dc_sample_callback_t callback, void *userdata, unsigned char code,
 		unsigned int offset, unsigned int time);
diff --git a/src/cochran_emc_parser.c b/src/cochran_emc_parser.c
index 8a554cb..5b4af81 100644
--- a/src/cochran_emc_parser.c
+++ b/src/cochran_emc_parser.c
@@ -52,13 +52,15 @@ dc_status_t
 cochran_emc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
 		unsigned int flags, void *value)
 {
-	cochran_data_t *data = (cochran_data_t *) abstract->data;
-	unsigned char *log = data->current_log;
+	const unsigned char *log = abstract->data + COCHRAN_MODEL_SIZE;
+	unsigned char corrupt_dive = 0;
+
+	if (array_uint32_le(log + COCHRAN_EMC_LOG_SIZE / 2) == 0xFFFFFFFF)
+		corrupt_dive = 1;
 
 	dc_gasmix_t *gasmix = (dc_gasmix_t *) value;
 	dc_salinity_t *water = (dc_salinity_t *) value;
 
-	unsigned int dive_time;
 	struct dive_stats stats;
 
 	if (value) {
@@ -67,28 +69,30 @@ cochran_emc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
 			*((unsigned int*) value) = ((float) log[EMC_START_TEMP] - 32) / 1.8;
 			break;
 		case DC_FIELD_TEMPERATURE_MINIMUM:
-			if (data->corrupt_dive) {
+			if (corrupt_dive) {
 				cochran_emc_parse_dive_stats(abstract, &stats);
 				*((unsigned int*) value) = stats.min_temp;
 			} else
-				*((unsigned int*) value) = ((float) log[EMC_MIN_TEMP] / 2 + 20 - 32) / 1.8;
+				*((unsigned int*) value) = ((float) log[EMC_MIN_TEMP] / 2
+					+ 20 - 32) / 1.8;
 			break;
 		case DC_FIELD_TEMPERATURE_MAXIMUM:
-			if (data->corrupt_dive) {
+			if (corrupt_dive) {
 				cochran_emc_parse_dive_stats(abstract, &stats);
 				*((unsigned int*) value) = stats.max_temp;
 			} else
-				*((unsigned int*) value) = ((float) log[EMC_MAX_TEMP] / 2 + 20 - 32) / 1.8;
+				*((unsigned int*) value) = ((float) log[EMC_MAX_TEMP] / 2
+					+ 20 - 32) / 1.8;
 			break;
 		case DC_FIELD_DIVETIME:
-			if (data->corrupt_dive) {
+			if (corrupt_dive) {
 				cochran_emc_parse_dive_stats(abstract, &stats);
 				*((unsigned int*) value) = stats.dive_time;
 			} else
 				*((unsigned int *) value) = array_uint16_le (log + EMC_BT) * 60;
 			break;
 		case DC_FIELD_MAXDEPTH:
-			if (data->corrupt_dive) {
+			if (corrupt_dive) {
 				cochran_emc_parse_dive_stats(abstract, &stats);
 				*((unsigned int*) value) = stats.max_depth;
 			} else
@@ -96,7 +100,7 @@ cochran_emc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
 						* FEET;
 			break;
 		case DC_FIELD_AVGDEPTH:
-			if (data->corrupt_dive) {
+			if (corrupt_dive) {
 				cochran_emc_parse_dive_stats(abstract, &stats);
 				*((unsigned int*) value) = stats.avg_depth;
 			} else
@@ -107,16 +111,16 @@ cochran_emc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
 			*((unsigned int *) value) = 10;
 			break;
 		case DC_FIELD_GASMIX:
-			gasmix->oxygen = (double) array_uint16_le ((char *) log
+			gasmix->oxygen = (double) array_uint16_le (log
 					+ EMC_O2_PERCENT + 2 * flags) / 256 / 100;
-			gasmix->helium = (double) array_uint16_le ((char *) log
+			gasmix->helium = (double) array_uint16_le (log
 					+ EMC_HE_PERCENT + 2 * flags) / 256 / 100;
 			gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium;
 			break;
 		case DC_FIELD_SALINITY:
 			// 0 = low conductivity, 2 = high, maybe there's a 1?
-			water->type = ( (log[EMC_WATER_CONDUCTIVITY] & 0x3) == 0 ? DC_WATER_FRESH
-					: DC_WATER_SALT );
+			water->type = ( (log[EMC_WATER_CONDUCTIVITY] & 0x3) == 0
+					? DC_WATER_FRESH : DC_WATER_SALT );
 			water->density = 1000 + 12.5 * (log[EMC_WATER_CONDUCTIVITY] & 0x3);
 			break;
 		case DC_FIELD_ATMOSPHERIC:
@@ -131,54 +135,17 @@ cochran_emc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type,
 	return DC_STATUS_SUCCESS;
 }
 
-/*
-*  For corrupt dives the end-of-samples pointer is 0xFFFFFFFF
-*  search for a reasonable size, e.g. using next dive start sample
-*  or end-of-samples to limit searching for recoverable samples
-*/
-static unsigned int
-cochran_emc_guess_sample_size(cochran_data_t *data)
-{
-	unsigned int size = 0;
-	unsigned int offset, next_offset, memory_start_offset, memory_end_offset;
-
-	// Get memory boundries
-	memory_start_offset = array_uint32_le(data->config[0] 
-		+ data->sample_memory_start_address);
-	memory_end_offset = array_uint32_le(data->config[0] 
-		+ data->sample_memory_end_address);
-
-	// see if there is a next sample
-	if (data->current_log - data->logbook + 512 >= data->logbook_size) {
-		// we are the last log entry, use maximum data
-		size = memory_end_offset - offset + 1;
-	} else {
-		offset = array_uint32_le(data->current_log + 6);
-		next_offset = array_uint32_le(data->current_log + 512 + 30);
-
-		if (next_offset >= offset) {
-			size = next_offset - offset + 1;
-		} else {
-			// samples wrap to begin of memory
-			size = memory_end_offset - offset + next_offset 
-				- memory_start_offset + 2;
-		}
-	}
-
-	return (size);
-}
-	
-
 
 dc_status_t
 cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
 		dc_sample_callback_t callback, void *userdata)
 {
-	cochran_data_t *data = (cochran_data_t *) abstract->data;
-	unsigned char *sdata = data->current_sample;
-	unsigned char *log = data->current_log;
-	unsigned int size = data->current_sample_size;
-	unsigned char *s;
+	const unsigned char *data = abstract->data;
+	const unsigned char *log = data + COCHRAN_MODEL_SIZE;
+	const unsigned char *samples = log + COCHRAN_EMC_LOG_SIZE;
+	unsigned int size = abstract->size - COCHRAN_MODEL_SIZE
+		- COCHRAN_EMC_LOG_SIZE;
+	const unsigned char *s;
 
 	dc_sample_value_t sample = {0}, empty_sample = {0};
 	unsigned int time = 0, last_sample_time;
@@ -188,18 +155,18 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
 	double ascent_rate;
 	unsigned char deco_obligation = 0;
 	unsigned int deco_ceiling = 0;
-	unsigned int deco_time = 0;
+	unsigned int deco_time;
+	unsigned char corrupt_dive = 0;
 
-	if (data->corrupt_dive) {
-		// Size of sample data is wrong, make a guess
-		size = cochran_emc_guess_sample_size(data);
-	}
+
+	if (array_uint32_le(log + COCHRAN_EMC_LOG_SIZE / 2) == 0xFFFFFFFF)
+		corrupt_dive = 1;
 
 	/*
 	 * Cochran samples depth every second and varies between ascent rate
 	 * and temp ever other second.
 	 * In the 21st, 22nd, 23rd, 24th samples are NDL remaining,
-	 *deco time and ceiling
+	 * deco time and ceiling
 	 */
 
 	// Prime with values from the dive log section
@@ -224,10 +191,10 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
 			callback (DC_SAMPLE_TIME, sample, userdata);
 		}
 
-		s = sdata + offset;
+		s = samples + offset;
 
 		// If corrupt_dive end before offset
-		if (data->corrupt_dive) {
+		if (corrupt_dive) {
 			if (   s[0] == 0x10
 				|| s[0] == 0xFF
 				|| s[0] == 0xA8) {
@@ -239,8 +206,8 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
 
 		// Check for event
 		if (s[0] & 0x80) {
-			offset += cochran_commander_handle_event(abstract, callback, userdata,
-				s[0], offset, time);
+			offset += cochran_commander_handle_event(abstract, callback,
+				userdata, s[0], offset, time);
 			switch (s[0])
 			{
 			case 0xC5:	// Deco obligation begins
@@ -262,7 +229,7 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
 
 				sample.deco.type = DC_DECO_DECOSTOP;
 				sample.deco.depth = deco_ceiling * FEET;
-				deco_time = (array_uint16_le(s + 3) + 1) * 60;
+				sample.deco.time = (array_uint16_le(s + 3) + 1) * 60;
 				if (callback) callback(DC_SAMPLE_DECO, sample, userdata);
 				break;
 			}
@@ -270,7 +237,7 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
 			continue;
 		}
 
-			
+
 		// Depth is logged as change in feet, bit 0x40 means negative depth
 		depth += (float) (s[0] & 0x3F) / 4 * (s[0] & 0x40 ? -1 : 1);
 		sample.depth = depth * FEET;
@@ -290,6 +257,17 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
 			if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata);
 		}
 
+		
+		// Some samples are split over two seconds
+		// Skip over event bytes to find the next sample
+		const unsigned char *n = s + COCHRAN_EMC_SAMPLE_SIZE;
+		cochran_events_t event;
+
+		while ((*n & 0x80) && n < s + size) {
+			cochran_commander_get_event_info(*n, &event);
+			n += event.data_bytes;
+		}
+
 		// Tissue load is in 20 samples, then 2 samples for RBT,
 		// and 2 for ceiling
 		switch (time % 24)
@@ -297,13 +275,14 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
 		case 20:
 			if (deco_obligation) {
 				/* Deco time for deepest stop, unused */
-				deco_time = (s[2] + s[5] * 256 + 1) * 60;
+				deco_time = (s[2] + n[2] * 256 + 1) * 60;
 			} else {
 				/* Get RBT */
-				sample.rbt = s[2] + s[5] * 256 + 1;
+				sample.rbt = s[2] + n[2] * 256 + 1;
 				if (callback) callback (DC_SAMPLE_RBT, sample, userdata);
 				/* Send deco NDL sample */
-				sample.deco.time = sample.rbt * 60; // seconds
+				sample.deco.type = DC_DECO_NDL;
+				sample.deco.time = (s[2] + n[2] * 256 + 1) * 60; // seconds
 				sample.deco.depth = 0;
 				if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
 			}
@@ -313,14 +292,14 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
 			if (deco_obligation) {
 				sample.deco.type = DC_DECO_DECOSTOP;
 				sample.deco.depth = deco_ceiling * FEET;
-				sample.deco.time = (s[2] + s[5] * 256 + 1) * 60; // minutes
+				sample.deco.time = (s[2] + n[2] * 256 + 1) * 60; // minutes
 				if (callback) callback (DC_SAMPLE_DECO, sample, userdata);
 			}
 			break;
 		}
 
 		time ++;
-		offset += 3;
+		offset += COCHRAN_EMC_SAMPLE_SIZE;
 	}
 
 	return DC_STATUS_SUCCESS;
@@ -329,51 +308,50 @@ cochran_emc_parser_samples_foreach (dc_parser_t *abstract,
 void cochran_emc_parse_dive_stats (dc_parser_t *abstract,
 		struct dive_stats *stats)
 {
-	cochran_data_t *data = (cochran_data_t *) abstract->data;
-	unsigned char *sdata = data->current_sample;
-	unsigned char *log = data->current_log;
-	unsigned int size = data->current_sample_size;
-	unsigned char *s;
+	const unsigned char *log = abstract->data + COCHRAN_MODEL_SIZE;
+	const unsigned char *samples = log + COCHRAN_EMC_LOG_SIZE;
+	unsigned int size = abstract->size - COCHRAN_MODEL_SIZE
+		- COCHRAN_EMC_LOG_SIZE;
+	const unsigned char *s;
+
 	unsigned int offset = 0;
-	cochran_events_t *e = cochran_events;
-	unsigned char event_ptr;
 	float depth_m = 0, depth, temp;
 	unsigned int time = 0; 
+	unsigned char corrupt_dive = 0;
 
-	// Check for corrupt dive
-	if (data->corrupt_dive)
-	{
-		// It's corrupt, guess at the sample size
-		size = cochran_emc_guess_sample_size(data);
-	}
+	if (array_uint32_le(log + COCHRAN_EMC_LOG_SIZE / 2) == 0xFFFFFFFF)
+		corrupt_dive = 1;
+
+	// Prime with values from the dive log section
+	depth = array_uint16_le (log + EMC_START_DEPTH) / 256;
 
-	stats->max_depth = 0;
+	stats->max_depth = depth;
 	stats->min_temp = 999;
 	stats->avg_depth = 0;
 	stats->max_temp = 0;
 
 	while (offset < size) {
-		s = sdata + offset;
+		s = samples + offset;
 
-		if (   s[0] == 0x10
-			|| s[0] == 0xFF
-			|| s[0] == 0xA8) {
+		if (corrupt_dive) {
+			if (s[0] == 0x10
+				|| s[0] == 0xFF
+				|| s[0] == 0xA8) {
 				// End corrupted dive
 				break;
+			}
+			if (time > 1 && (s[0] == 0xE3 || s[0] == 0xF3))
+				break;
 		}
 
-		if (time > 1 && (s[0] == 0xE3 || s[0] == 0xF3))
-			break;
-
 		// Check for event
 		if (s[0] & 0x80) {
-			event_ptr = 0;
-			while (e[event_ptr].code && e[event_ptr].code != s[0])
-				event_ptr++;
+			cochran_events_t event;
+			cochran_commander_get_event_info(s[0], &event);
 
 			// Advance some bytes
-			if (e[event_ptr].code)
-				offset += e[event_ptr].data_bytes;
+			if (event.code)
+				offset += event.data_bytes;
 			else
 				offset ++;
 
@@ -390,7 +368,7 @@ void cochran_emc_parse_dive_stats (dc_parser_t *abstract,
 
 		if (time % 2 != 0) {
 			// Temperature logged in half degrees F above 20
-			temp = s[1] / 2 + 20;
+			temp = (float) s[1] / 2 + 20;
 			temp = (temp - 32.0) / 1.8;
 
 			if (temp < stats->min_temp) stats->min_temp = temp;
@@ -398,7 +376,7 @@ void cochran_emc_parse_dive_stats (dc_parser_t *abstract,
 		}
 
 		time ++;
-		offset += 3;
+		offset += COCHRAN_EMC_SAMPLE_SIZE;
 	}
 
 	stats->dive_time = time - 1;
-- 
1.8.3.1



More information about the devel mailing list