[PATCH] Cochran: Added support for Pre-21000 s/n Commander dive computers

John Van Ostrand john at vanostrand.com
Fri Jun 2 16:51:28 PDT 2017


This adds support for older Cochran Commander dive computers,
specifically Commanders with serial numbers prior to 21000.

This also renames "Commander" model to "Commander II" and
adds "Commander I" to refer to pre-21000 models.

This commit also fixes problems with dive computers where the
log ringbuffer has wrapped.
---
 src/array.c                    |   7 ++
 src/array.h                    |   3 +
 src/cochran_commander.c        | 155 +++++++++++++++++++++++++++++++++--------
 src/cochran_commander_parser.c |  83 +++++++++++++++++++---
 src/descriptor.c               |   9 +--
 5 files changed, 213 insertions(+), 44 deletions(-)

diff --git a/src/array.c b/src/array.c
index 13a73e5..5574083 100644
--- a/src/array.c
+++ b/src/array.c
@@ -198,6 +198,13 @@ array_uint32_le (const unsigned char data[])
 }
 
 
+unsigned int
+array_uint32_word_be (const unsigned char data[])
+{
+	return data[1] + (data[0] << 8) + (data[3] << 16) + (data[2] << 24);
+}
+
+
 void
 array_uint32_le_set (unsigned char data[], const unsigned int input)
 {
diff --git a/src/array.h b/src/array.h
index cd0a3a1..da70efa 100644
--- a/src/array.h
+++ b/src/array.h
@@ -64,6 +64,9 @@ array_uint32_be (const unsigned char data[]);
 unsigned int
 array_uint32_le (const unsigned char data[]);
 
+unsigned int
+array_uint32_word_be (const unsigned char data[]);
+
 void
 array_uint32_le_set (unsigned char data[], const unsigned int input);
 
diff --git a/src/cochran_commander.c b/src/cochran_commander.c
index b3e5fed..1c1009f 100644
--- a/src/cochran_commander.c
+++ b/src/cochran_commander.c
@@ -32,14 +32,16 @@
 
 #define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
 
-#define COCHRAN_MODEL_COMMANDER_AIR_NITROX 0
-#define COCHRAN_MODEL_EMC_14 1
-#define COCHRAN_MODEL_EMC_16 2
-#define COCHRAN_MODEL_EMC_20 3
+#define COCHRAN_MODEL_COMMANDER_PRE21000 0
+#define COCHRAN_MODEL_COMMANDER_AIR_NITROX 1
+#define COCHRAN_MODEL_EMC_14 2
+#define COCHRAN_MODEL_EMC_16 3
+#define COCHRAN_MODEL_EMC_20 4
 
 typedef enum cochran_endian_t {
 	ENDIAN_LE,
 	ENDIAN_BE,
+	ENDIAN_WORD_BE,
 } cochran_endian_t;
 
 typedef enum cochran_profile_size_t {
@@ -48,7 +50,7 @@ typedef enum cochran_profile_size_t {
 } cochran_profile_size_t;
 
 typedef struct cochran_commander_model_t {
-	unsigned char id[2 + 1];
+	unsigned char id[3 + 1];
 	unsigned int model;
 } cochran_commander_model_t;
 
@@ -84,7 +86,9 @@ typedef struct cochran_device_layout_t {
 	// Profile ringbuffer.
 	unsigned int rb_profile_begin;
 	unsigned int rb_profile_end;
-	// Profile pointers.
+	// pointers.
+	unsigned int pt_fingerprint;
+	unsigned int fingerprint_size;
 	unsigned int pt_profile_pre;
 	unsigned int pt_profile_begin;
 	unsigned int pt_profile_end;
@@ -115,6 +119,30 @@ static const dc_device_vtable_t cochran_commander_device_vtable = {
 	cochran_commander_device_close /* close */
 };
 
+// Cochran Commander pre-21000 s/n
+static const cochran_device_layout_t cochran_cmdr_1_device_layout = {
+	COCHRAN_MODEL_COMMANDER_PRE21000, // model
+	24,         // address_bits
+	ENDIAN_WORD_BE,  // endian
+	115200,     // baudrate
+	0x046,      // cf_dive_count
+	0x6c,       // cf_last_log
+	0x70,       // cf_last_interdive
+	0x0AA,      // cf_serial_number
+	0x00000000, // rb_logbook_begin
+	0x00020000, // rb_logbook_end
+	256,        // rb_logbook_entry_size
+	512,        // rb_logbook_entry_count
+	0x00020000, // rb_profile_begin
+	0x00100000, // rb_profile_end
+	12,         // pt_fingerprint
+	4,          // fingerprint_size
+	28,         // pt_profile_pre
+	0,          // pt_profile_begin
+	128,        // pt_profile_end
+};
+
+
 // Cochran Commander Nitrox
 static const cochran_device_layout_t cochran_cmdr_device_layout = {
 	COCHRAN_MODEL_COMMANDER_AIR_NITROX, // model
@@ -131,6 +159,8 @@ static const cochran_device_layout_t cochran_cmdr_device_layout = {
 	512,        // rb_logbook_entry_count
 	0x00020000, // rb_profile_begin
 	0x00100000, // rb_profile_end
+	0,          // pt_fingerprint
+	6,          // fingerprint_size
 	30,         // pt_profile_pre
 	6,          // pt_profile_begin
 	128,        // pt_profile_end
@@ -152,6 +182,8 @@ static const cochran_device_layout_t cochran_emc14_device_layout = {
 	256,        // rb_logbook_entry_count
 	0x00022000, // rb_profile_begin
 	0x00200000, // rb_profile_end
+	0,          // pt_fingerprint
+	6,          // fingerprint_size
 	30,         // pt_profile_pre
 	6,          // pt_profile_begin
 	256,        // pt_profile_end
@@ -173,6 +205,8 @@ static const cochran_device_layout_t cochran_emc16_device_layout = {
 	1024,       // rb_logbook_entry_count
 	0x00094000, // rb_profile_begin
 	0x00800000, // rb_profile_end
+	0,          // pt_fingerprint
+	6,          // fingerprint_size
 	30,         // pt_profile_pre
 	6,          // pt_profile_begin
 	256,        // pt_profile_end
@@ -194,6 +228,8 @@ static const cochran_device_layout_t cochran_emc20_device_layout = {
 	1024,       // rb_logbook_entry_count
 	0x00094000, // rb_profile_begin
 	0x01000000, // rb_profile_end
+	0,          // pt_fingerprint
+	6,          // fingerprint_size
 	30,         // pt_profile_pre
 	6,          // pt_profile_begin
 	256,        // pt_profile_end
@@ -205,10 +241,12 @@ static unsigned int
 cochran_commander_get_model (cochran_commander_device_t *device)
 {
 	const cochran_commander_model_t models[] = {
-		{"\x11""2", COCHRAN_MODEL_COMMANDER_AIR_NITROX},
-		{"73",      COCHRAN_MODEL_EMC_14},
-		{"A3",      COCHRAN_MODEL_EMC_16},
-		{"23",      COCHRAN_MODEL_EMC_20},
+		{"\x11""21", COCHRAN_MODEL_COMMANDER_PRE21000},
+		{"\x11""22", COCHRAN_MODEL_COMMANDER_AIR_NITROX},
+		{"730",      COCHRAN_MODEL_EMC_14},
+		{"A30",      COCHRAN_MODEL_EMC_16},
+		{"230",      COCHRAN_MODEL_EMC_20},
+		{"231",      COCHRAN_MODEL_EMC_20},
 	};
 
 	unsigned int model = 0xFFFFFFFF;
@@ -501,6 +539,7 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d
 	int profile_capacity_remaining = device->layout->rb_profile_end - device->layout->rb_profile_begin;
 
 	int dive_count = -1;
+	data->fp_dive_num = -1;
 
 	// Start at end of log
 	if (data->dive_count < device->layout->rb_logbook_entry_count)
@@ -513,18 +552,36 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d
 	data->invalid_profile_dive_num = -1;
 
 	// Remove the pre-dive events that occur after the last dive
-	int rb_head_ptr = (array_uint32_le(data->config + device->layout->cf_last_interdive) & 0xfffff000) + 0x2000;
+	int rb_head_ptr;
+	if (device->layout->endian == ENDIAN_WORD_BE)
+		rb_head_ptr = (array_uint32_word_be(data->config + device->layout->cf_last_interdive) & 0xfffff000) + 0x2000;
+	else
+		rb_head_ptr = (array_uint32_le(data->config + device->layout->cf_last_interdive) & 0xfffff000) + 0x2000;
 	int last_dive_end_address = array_uint32_le(data->logbook + dive_count * device->layout->rb_logbook_entry_size + device->layout->pt_profile_end);
 	if (rb_head_ptr > last_dive_end_address)
 		profile_capacity_remaining -= rb_head_ptr - last_dive_end_address;
 
+	unsigned int head_dive = 0, tail_dive = 0;
+
+	if (data->dive_count <= device->layout->rb_logbook_entry_count) {
+		head_dive = data->dive_count;
+		tail_dive = 0;
+	} else {
+		// Log wrapped
+		tail_dive = data->dive_count % device->layout->rb_logbook_entry_count;
+		head_dive = tail_dive;
+	}
+
 	// Loop through dives to find FP, Accumulate profile data size,
 	// and find the last dive with invalid profile
-	for (int i = dive_count; i > 0; i--) {
+	unsigned int i = head_dive;
+	do {
+		i = ringbuffer_decrement(i, 1, 0, device->layout->rb_logbook_entry_count);
+
 		unsigned char *log_entry = data->logbook + i * device->layout->rb_logbook_entry_size;
 
 		// We're done if we find the fingerprint
-		if (!memcmp(device->fingerprint, log_entry, sizeof(device->fingerprint))) {
+		if (!memcmp(device->fingerprint, log_entry + device->layout->pt_fingerprint, device->layout->fingerprint_size)) {
 			data->fp_dive_num = i;
 			break;
 		}
@@ -543,7 +600,7 @@ cochran_commander_find_fingerprint(cochran_commander_device_t *device, cochran_d
 			// Accumulate read size for progress bar
 			sample_read_size += read_size;
 		}
-	}
+	} while (i != tail_dive);
 
 	return sample_read_size;
 }
@@ -653,6 +710,9 @@ cochran_commander_device_open (dc_device_t **out, dc_context_t *context, const c
 
 	unsigned int model = cochran_commander_get_model(device);
 	switch (model) {
+	case COCHRAN_MODEL_COMMANDER_PRE21000:
+		device->layout = &cochran_cmdr_1_device_layout;
+		break;
 	case COCHRAN_MODEL_COMMANDER_AIR_NITROX:
 		device->layout = &cochran_cmdr_device_layout;
 		break;
@@ -703,13 +763,13 @@ cochran_commander_device_set_fingerprint (dc_device_t *abstract, const unsigned
 {
 	cochran_commander_device_t *device = (cochran_commander_device_t *) abstract;
 
-	if (size && size != sizeof (device->fingerprint))
+	if (size && size != device->layout->fingerprint_size)
 		return DC_STATUS_INVALIDARGS;
 
 	if (size)
-		memcpy (device->fingerprint, data, sizeof (device->fingerprint));
+		memcpy (device->fingerprint, data, device->layout->fingerprint_size);
 	else
-		memset (device->fingerprint, 0xFF, sizeof (device->fingerprint));
+		memset (device->fingerprint, 0xFF, sizeof(device->fingerprint));
 
 	return DC_STATUS_SUCCESS;
 }
@@ -806,9 +866,13 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
 	else
 		data.dive_count = array_uint16_be (data.config + device->layout->cf_dive_count);
 
+	if (data.dive_count == 0)
+		// No dives to read
+		return DC_STATUS_SUCCESS;
+
 	if (data.dive_count > device->layout->rb_logbook_entry_count) {
 		data.logbook_size = device->layout->rb_logbook_entry_count * device->layout->rb_logbook_entry_size;
-    } else {
+	} else {
 		data.logbook_size = data.dive_count * device->layout->rb_logbook_entry_size;
 	}
 
@@ -842,26 +906,47 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
 	dc_event_devinfo_t devinfo;
 	devinfo.model = device->layout->model;
 	devinfo.firmware = 0; // unknown
-	devinfo.serial = array_uint32_le(data.config + device->layout->cf_serial_number);
+	if (device->layout->endian == ENDIAN_WORD_BE)
+		devinfo.serial = array_uint32_word_be(data.config + device->layout->cf_serial_number);
+	else
+		devinfo.serial = array_uint32_le(data.config + device->layout->cf_serial_number);
+
 	device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
 
 	// Calculate profile RB effective head pointer
 	// Cochran seems to erase 8K chunks so round up.
-	unsigned int last_start_address = (array_uint32_le(data.config + device->layout->cf_last_interdive) & 0xfffff000) + 0x2000;
+	unsigned int last_start_address;
+	if (device->layout->endian == ENDIAN_WORD_BE)
+		last_start_address = (array_uint32_word_be(data.config + device->layout->cf_last_interdive) & 0xfffff000) + 0x2000;
+	else
+		last_start_address = (array_uint32_le(data.config + device->layout->cf_last_interdive) & 0xfffff000) + 0x2000;
+
 	if (last_start_address < device->layout->rb_profile_begin || last_start_address > device->layout->rb_profile_end) {
 		ERROR(abstract->context, "Invalid profile ringbuffer head pointer in Cochran config block.");
 		status = DC_STATUS_DATAFORMAT;
 		goto error;
 	}
 
-	unsigned int dive_count = 0;
-	if (data.dive_count < device->layout->rb_logbook_entry_count)
-		dive_count = data.dive_count;
-	else
-		dive_count = device->layout->rb_logbook_entry_count;
+	unsigned int head_dive = 0, tail_dive = 0;
+
+	if (data.dive_count <= device->layout->rb_logbook_entry_count) {
+		head_dive = data.dive_count;
+		tail_dive = 0;
+	} else {
+		// Log wrapped
+		tail_dive = data.dive_count % device->layout->rb_logbook_entry_count;
+		head_dive = tail_dive;
+	}
+	if (data.fp_dive_num > -1)
+		tail_dive = data.fp_dive_num + 1;
+
+	int invalid_profile_flag = 0;
 
 	// Loop through each dive
-	for (int i = dive_count - 1; i > data.fp_dive_num; i--) {
+	unsigned int i = head_dive;
+	do {
+		i = ringbuffer_decrement(i, 1, 0, device->layout->rb_logbook_entry_count);
+
 		unsigned char *log_entry = data.logbook + i * device->layout->rb_logbook_entry_size;
 
 		unsigned int sample_start_address = array_uint32_le (log_entry + device->layout->pt_profile_begin);
@@ -870,7 +955,10 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
 		int sample_size = 0;
 
 		// Determine if profile exists
-		if (i > data.invalid_profile_dive_num)
+		if (i == data.invalid_profile_dive_num)
+			invalid_profile_flag = 1;
+
+		if (!invalid_profile_flag)
 			sample_size = cochran_commander_profile_size(device, &data, i, PROFILE_SIZE_READ);
 
 		// Build dive blob
@@ -892,7 +980,10 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
 
 			if (sample_start_address <= sample_end_address) {
 				do {
+					int saved_progress = progress.current;
 					rc = cochran_commander_read (device, &progress, sample_start_address, dive + device->layout->rb_logbook_entry_size, sample_size);
+					if (rc != DC_STATUS_SUCCESS)
+						progress.current = saved_progress;
 				} while (rc != DC_STATUS_SUCCESS && tries++ < 3);
 				if (rc != DC_STATUS_SUCCESS) {
 					ERROR (abstract->context, "Failed to read the sample data.");
@@ -905,7 +996,10 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
 
 				tries = 0;
 				do {
+					int saved_progress = progress.current;
 					rc = cochran_commander_read (device, &progress, sample_start_address, dive + device->layout->rb_logbook_entry_size, size);
+					if (rc != DC_STATUS_SUCCESS)
+						progress.current = saved_progress;
 				} while (rc != DC_STATUS_SUCCESS && tries++ < 3);
 				if (rc != DC_STATUS_SUCCESS) {
 					ERROR (abstract->context, "Failed to read the sample data.");
@@ -914,7 +1008,10 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
 				}
 				tries = 0;
 				do {
+					int saved_progress = progress.current;
 					rc = cochran_commander_read (device, &progress, device->layout->rb_profile_begin, dive + device->layout->rb_logbook_entry_size + size, sample_end_address - device->layout->rb_profile_begin);
+					if (rc != DC_STATUS_SUCCESS)
+						progress.current = saved_progress;
 				} while (rc != DC_STATUS_SUCCESS && tries++ < 3);
 				if (rc != DC_STATUS_SUCCESS) {
 					ERROR (abstract->context, "Failed to read the sample data.");
@@ -924,13 +1021,13 @@ cochran_commander_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
 			}
 		}
 
-		if (callback && !callback (dive, dive_size, dive, sizeof(device->fingerprint), userdata)) {
+		if (callback && !callback (dive, dive_size, dive + device->layout->pt_fingerprint, device->layout->fingerprint_size, userdata)) {
 			free(dive);
 			break;
 		}
 
 		free(dive);
-	}
+	} while (i != tail_dive);
 
 error:
 	free(data.logbook);
diff --git a/src/cochran_commander_parser.c b/src/cochran_commander_parser.c
index ab854ad..d9521c0 100644
--- a/src/cochran_commander_parser.c
+++ b/src/cochran_commander_parser.c
@@ -21,6 +21,7 @@
 
 #include <stdlib.h>
 #include <math.h>
+#include <time.h>
 
 #include <libdivecomputer/units.h>
 
@@ -31,10 +32,14 @@
 
 #define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
 
-#define COCHRAN_MODEL_COMMANDER_AIR_NITROX 0
-#define COCHRAN_MODEL_EMC_14 1
-#define COCHRAN_MODEL_EMC_16 2
-#define COCHRAN_MODEL_EMC_20 3
+#define COCHRAN_MODEL_COMMANDER_PRE21000 0
+#define COCHRAN_MODEL_COMMANDER_AIR_NITROX 1
+#define COCHRAN_MODEL_EMC_14 2
+#define COCHRAN_MODEL_EMC_16 3
+#define COCHRAN_MODEL_EMC_20 4
+
+// Cochran time stamps start at Jan 1, 1992
+#define COCHRAN_TIME_SHIFT 694242000
 
 #define UNSUPPORTED 0xFFFFFFFF
 
@@ -43,11 +48,19 @@ typedef enum cochran_sample_format_t {
 	SAMPLE_EMC,
 } cochran_sample_format_t;
 
+
+typedef enum cochran_date_encoding_t {
+	DATE_ENCODING_ELEMENTAL,
+	DATE_ENCODING_SECONDS_SINCE,
+} cochran_date_encoding_t;
+
 typedef struct cochran_parser_layout_t {
 	cochran_sample_format_t format;
 	unsigned int headersize;
 	unsigned int samplesize;
+	cochran_date_encoding_t date_encoding;
 	unsigned int second, minute, hour, day, month, year;
+	unsigned int timestamp;
 	unsigned int pt_profile_begin;
 	unsigned int water_conductivity;
 	unsigned int pt_profile_pre;
@@ -101,11 +114,38 @@ static const dc_parser_vtable_t cochran_commander_parser_vtable = {
 	NULL /* destroy */
 };
 
+static const cochran_parser_layout_t cochran_cmdr_1_parser_layout = {
+	SAMPLE_CMDR, // type
+	256,         // headersize
+	2,           // samplesize
+	DATE_ENCODING_SECONDS_SINCE, // date_encoding
+	1, 0, 3, 2, 5, 4, // second, minute, hour, day, month, year, 1 byte each
+	8,           // timestamp, 4 bytes
+	0,           // pt_profile_begin, 4 bytes
+	24,          // water_conductivity, 1 byte, 0=low(fresh), 2=high(sea)
+	28,          // pt_profile_pre, 4 bytes
+	43,          // start_temp, 1 byte, F
+	54,          // start_depth, 2 bytes, /4=ft
+	68,          // dive_number, 2 bytes
+	73,          // altitude, 1 byte, /4=kilofeet
+	128,         // pt_profile_end, 4 bytes
+	153,         // end_temp, 1 byte F
+	166,         // divetime, 2 bytes, minutes
+	168,         // max_depth, 2 bytes, /4=ft
+	170,         // avg_depth, 2 bytes, /4=ft
+	210,         // oxygen, 4 bytes (2 of) 2 bytes, /256=%
+	UNSUPPORTED, // helium, 4 bytes (2 of) 2 bytes, /256=%
+	232,         // min_temp, 1 byte, /2+20=F
+	233,         // max_temp, 1 byte, /2+20=F
+};
+
 static const cochran_parser_layout_t cochran_cmdr_parser_layout = {
 	SAMPLE_CMDR, // type
 	256,         // headersize
 	2,           // samplesize
+	DATE_ENCODING_ELEMENTAL, // date_encoding
 	1, 0, 3, 2, 5, 4, // second, minute, hour, day, month, year, 1 byte each
+	0,           // timestamp, 4 bytes
 	6,           // pt_profile_begin, 4 bytes
 	24,          // water_conductivity, 1 byte, 0=low(fresh), 2=high(sea)
 	30,          // pt_profile_pre, 4 bytes
@@ -128,7 +168,9 @@ static const cochran_parser_layout_t cochran_emc_parser_layout = {
 	SAMPLE_EMC,  // type
 	512,         // headersize
 	3,           // samplesize
+	DATE_ENCODING_ELEMENTAL, // date_encoding
 	0, 1, 2, 3, 4, 5, // second, minute, hour, day, month, year, 1 byte each
+	0,           // timestamp, 4 bytes
 	6,           // pt_profile_begin, 4 bytes
 	24,          // water_conductivity, 1 byte 0=low(fresh), 2=high(sea)
 	30,          // pt_profile_pre, 4 bytes
@@ -296,6 +338,11 @@ cochran_commander_parser_create (dc_parser_t **out, dc_context_t *context, unsig
 	parser->model = model;
 
 	switch (model) {
+	case COCHRAN_MODEL_COMMANDER_PRE21000:
+		parser->layout = &cochran_cmdr_1_parser_layout;
+		parser->events = cochran_cmdr_event_bytes;
+		parser->nevents = C_ARRAY_SIZE(cochran_cmdr_event_bytes);
+		break;
 	case COCHRAN_MODEL_COMMANDER_AIR_NITROX:
 		parser->layout = &cochran_cmdr_parser_layout;
 		parser->events = cochran_cmdr_event_bytes;
@@ -341,12 +388,25 @@ cochran_commander_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *dat
 		return DC_STATUS_DATAFORMAT;
 
 	if (datetime) {
-		datetime->second = data[layout->second];
-		datetime->minute = data[layout->minute];
-		datetime->hour = data[layout->hour];
-		datetime->day = data[layout->day];
-		datetime->month = data[layout->month];
-		datetime->year = data[layout->year] + (data[layout->year] > 91 ? 1900 : 2000);
+		if (layout->date_encoding == DATE_ENCODING_SECONDS_SINCE) {
+			time_t ts;
+			struct tm *t;
+			ts = array_uint32_le(data + layout->timestamp) + COCHRAN_TIME_SHIFT;
+			t = localtime(&ts);
+			datetime->second = t->tm_sec;
+			datetime->minute = t->tm_min;
+			datetime->hour = t->tm_hour;
+			datetime->day = t->tm_mday;
+			datetime->month = t->tm_mon + 1;
+			datetime->year = 1900 + t->tm_year;
+		} else {
+			datetime->second = data[layout->second];
+			datetime->minute = data[layout->minute];
+			datetime->hour = data[layout->hour];
+			datetime->day = data[layout->day];
+			datetime->month = data[layout->month];
+			datetime->year = data[layout->year] + (data[layout->year] > 91 ? 1900 : 2000);
+		}
 	}
 
 	return DC_STATUS_SUCCESS;
@@ -484,7 +544,8 @@ cochran_commander_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callb
 	// and temp every other second.
 
 	// Prime values from the dive log section
-	if (parser->model == COCHRAN_MODEL_COMMANDER_AIR_NITROX) {
+	if (parser->model == COCHRAN_MODEL_COMMANDER_AIR_NITROX ||
+		parser->model == COCHRAN_MODEL_COMMANDER_PRE21000) {
 		// Commander stores start depth in quarter-feet
 		start_depth = array_uint16_le (data + layout->start_depth) / 4.0;
 	} else {
diff --git a/src/descriptor.c b/src/descriptor.c
index b59ea45..76157da 100644
--- a/src/descriptor.c
+++ b/src/descriptor.c
@@ -292,10 +292,11 @@ static const dc_descriptor_t g_descriptors[] = {
 	{"DiveSystem", "iX3M Deep",     DC_FAMILY_DIVESYSTEM_IDIVE, 0x23},
 	{"DiveSystem", "iX3M Tec",      DC_FAMILY_DIVESYSTEM_IDIVE, 0x24},
 	{"DiveSystem", "iX3M Reb",      DC_FAMILY_DIVESYSTEM_IDIVE, 0x25},
-	{"Cochran", "Commander",	DC_FAMILY_COCHRAN_COMMANDER, 0},
-	{"Cochran", "EMC-14",		DC_FAMILY_COCHRAN_COMMANDER, 1},
-	{"Cochran", "EMC-16",		DC_FAMILY_COCHRAN_COMMANDER, 2},
-	{"Cochran", "EMC-20H",		DC_FAMILY_COCHRAN_COMMANDER, 3},
+	{"Cochran", "Commander I",	DC_FAMILY_COCHRAN_COMMANDER, 0},
+	{"Cochran", "Commander II",	DC_FAMILY_COCHRAN_COMMANDER, 1},
+	{"Cochran", "EMC-14",		DC_FAMILY_COCHRAN_COMMANDER, 2},
+	{"Cochran", "EMC-16",		DC_FAMILY_COCHRAN_COMMANDER, 3},
+	{"Cochran", "EMC-20H",		DC_FAMILY_COCHRAN_COMMANDER, 4},
 };
 
 typedef struct dc_descriptor_iterator_t {
-- 
2.4.11



More information about the devel mailing list