From 906ee8db3b5a192d291b8fc27a26172315449633 Mon Sep 17 00:00:00 2001
From: Dirk Hohndel <dirk@hohndel.org>
Date: Wed, 24 Sep 2014 21:39:28 -0700
Subject: [PATCH 1/4] Add initial support for the Aeris A300CS

This is ignoring a ton of data that the dive computer provides. But it
gives profile, tank pressure and temperatures - so it's a start.

This patch adds a set_dtr and set_rts call to the serial interface prior
to interacting with the device. This change is required for the A300CS to
talk to the computer.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
---
 src/descriptor.c           |  1 +
 src/oceanic_atom2.c        | 23 +++++++++++++++++++++++
 src/oceanic_atom2_parser.c | 35 ++++++++++++++++++++++++++++++-----
 3 files changed, 54 insertions(+), 5 deletions(-)

diff --git a/src/descriptor.c b/src/descriptor.c
index 403b67a..617c279 100644
--- a/src/descriptor.c
+++ b/src/descriptor.c
@@ -171,6 +171,7 @@ static const dc_descriptor_t g_descriptors[] = {
 	{"Sherwood", "Amphos",              DC_FAMILY_OCEANIC_ATOM2, 0x4545},
 	{"Oceanic",  "Pro Plus 3",          DC_FAMILY_OCEANIC_ATOM2, 0x4548},
 	{"Oceanic",  "OCi",                 DC_FAMILY_OCEANIC_ATOM2, 0x454B},
+	{"Aeris",    "A300CS",              DC_FAMILY_OCEANIC_ATOM2, 0x454C},
 	/* Mares Nemo */
 	{"Mares", "Nemo",         DC_FAMILY_MARES_NEMO, 0},
 	{"Mares", "Nemo Steel",   DC_FAMILY_MARES_NEMO, 0},
diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c
index 17e1958..f507241 100644
--- a/src/oceanic_atom2.c
+++ b/src/oceanic_atom2.c
@@ -149,6 +149,10 @@ static const oceanic_common_version_t oceanic_reactpro_version[] = {
 	{"REACPRO2 \0\0 512K"},
 };
 
+static const oceanic_common_version_t aeris_a300cs_version[] = {
+	{"AER300CS \0\0 2048"},
+};
+
 static const oceanic_common_layout_t aeris_f10_layout = {
 	0x10000, /* memsize */
 	0x0000, /* cf_devinfo */
@@ -331,6 +335,19 @@ static const oceanic_common_layout_t oceanic_reactpro_layout = {
 	1 /* pt_mode_logbook */
 };
 
+static const oceanic_common_layout_t aeris_a300cs_layout = {
+	0x40000, /* memsize */
+	0x0000, /* cf_devinfo */
+	0x0040, /* cf_pointers */
+	0x0900, /* rb_logbook_begin */
+	0x1000, /* rb_logbook_end */
+	16, /* rb_logbook_entry_size */
+	0x1000, /* rb_profile_begin */
+	0x3FE00, /* rb_profile_end */
+	0, /* pt_mode_global */
+	1 /* pt_mode_logbook */
+};
+
 static dc_status_t
 oceanic_atom2_send (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char ack)
 {
@@ -480,6 +497,10 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char
 	// Give the interface 100 ms to settle and draw power up.
 	serial_sleep (device->port, 100);
 
+	// Set the DTR/RTS lines.
+	serial_set_dtr(device->port, 1);
+	serial_set_rts(device->port, 1);
+
 	// Make sure everything is in a sane state.
 	serial_flush (device->port, SERIAL_QUEUE_BOTH);
 
@@ -526,6 +547,8 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char
 		device->base.layout = &oceanic_veo1_layout;
 	} else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_reactpro_version)) {
 		device->base.layout = &oceanic_reactpro_layout;
+	} else if (OCEANIC_COMMON_MATCH (device->base.version, aeris_a300cs_version)) {
+		device->base.layout = &aeris_a300cs_layout;
 	} else {
 		device->base.layout = &oceanic_default_layout;
 	}
diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c
index beed0a8..a4832a1 100644
--- a/src/oceanic_atom2_parser.c
+++ b/src/oceanic_atom2_parser.c
@@ -69,6 +69,7 @@
 #define AMPHOS      0x4545
 #define PROPLUS3    0x4548
 #define OCI         0x454B
+#define A300CS      0x454C
 
 typedef struct oceanic_atom2_parser_t oceanic_atom2_parser_t;
 
@@ -218,6 +219,13 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim
 			datetime->hour   = p[11];
 			datetime->minute = p[10];
 			break;
+		case A300CS:
+			datetime->year   = (p[10]) + 2000;
+			datetime->month  = (p[8]);
+			datetime->day    = (p[9]);
+			datetime->hour   = bcd2dec(p[1] & 0x1F);
+			datetime->minute = bcd2dec(p[0]);
+			break;
 		default:
 			datetime->year   = bcd2dec (((p[3] & 0xC0) >> 2) + (p[4] & 0x0F)) + 2000;
 			datetime->month  = (p[4] & 0xF0) >> 4;
@@ -345,7 +353,8 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
 		case DC_FIELD_GASMIX_COUNT:
 			if (parser->model == DATAMASK || parser->model == COMPUMASK)
 				*((unsigned int *) value) = 1;
-			else if (parser->model == VT4 || parser->model == VT41 || parser->model == OCI)
+			else if (parser->model == VT4 || parser->model == VT41 ||
+				parser->model == OCI || parser->model == A300CS)
 				*((unsigned int *) value) = 4;
 			else if (parser->model == TX1)
 				*((unsigned int *) value) = 6;
@@ -357,6 +366,8 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
 				oxygen = data[header + 3];
 			} else if (parser->model == OCI) {
 				oxygen = data[0x28 + flags];
+			} else if (parser->model == A300CS) {
+				oxygen = data[0x2A + flags];
 			} else if (parser->model == TX1) {
 				oxygen = data[0x3E + flags];
 				helium = data[0x48 + flags];
@@ -403,6 +414,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
 	} else if (parser->model == F10) {
 		headersize = 3 * PAGESIZE;
 		footersize = PAGESIZE / 2;
+	} else if (parser->model == A300CS) {
+		headersize = 5 * PAGESIZE;
 	}
 
 	if (size < headersize + footersize)
@@ -414,7 +427,10 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
 	unsigned int time = 0;
 	unsigned int interval = 1;
 	if (parser->model != F10) {
-		switch (data[0x17] & 0x03) {
+		unsigned int idx = 0x17;
+		if (parser->model == A300CS)
+			idx = 0x1f;
+		switch (data[idx] & 0x03) {
 		case 0:
 			interval = 2;
 			break;
@@ -433,7 +449,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
 	unsigned int samplesize = PAGESIZE / 2;
 	if (parser->model == OC1A || parser->model == OC1B ||
 		parser->model == OC1C || parser->model == OCI ||
-		parser->model == TX1)
+		parser->model == TX1 || parser->model == A300CS)
 		samplesize = PAGESIZE;
 	else if (parser->model == F10)
 		samplesize = 2;
@@ -458,7 +474,10 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
 	unsigned int tank = 0;
 	unsigned int pressure = 0;
 	if (have_pressure) {
-		pressure = data[header + 2] + (data[header + 3] << 8);
+		unsigned int idx = 2;
+		if (parser->model == A300CS)
+			idx = 16;
+		pressure = data[header + idx] + (data[header + idx + 1] << 8);
 		if (pressure == 10000)
 			have_pressure = 0;
 	}
@@ -510,6 +529,10 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
 				// Tank pressure (1 psi) and number
 				tank = 0;
 				pressure = (((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF);
+			} else if (parser->model == A300CS) {
+				// Tank pressure (1 psi) and number (one based index)
+				tank = (data[offset + 1] & 0x03) - 1;
+				pressure = ((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF;
 			} else {
 				// Tank pressure (2 psi) and number (one based index)
 				tank = (data[offset + 1] & 0x03) - 1;
@@ -551,6 +574,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
 					temperature = data[offset + 1];
 				} else if (parser->model == VT4 || parser->model == VT41 || parser->model == ATOM3 || parser->model == ATOM31 || parser->model == A300AI) {
 					temperature = ((data[offset + 7] & 0xF0) >> 4) | ((data[offset + 7] & 0x0C) << 2) | ((data[offset + 5] & 0x0C) << 4);
+				} else if (parser->model == A300CS) {
+					temperature = data[offset + 11];
 				} else {
 					unsigned int sign;
 					if (parser->model == DG03 || parser->model == PROPLUS3)
@@ -583,7 +608,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
 					parser->model == ZENAIR ||parser->model == A300AI ||
 					parser->model == DG03 || parser->model == PROPLUS3)
 					pressure = (((data[offset + 0] & 0x03) << 8) + data[offset + 1]) * 5;
-				else if (parser->model == TX1)
+				else if (parser->model == TX1 || parser->model == A300CS)
 					pressure = array_uint16_le (data + offset + 4);
 				else
 					pressure -= data[offset + 1];
-- 
1.9.1

