first stab at Aeris A300CS support

Dirk Hohndel dirk at hohndel.org
Thu Sep 25 21:12:19 PDT 2014


This implements fairly basic support for the A300CS

- adds a cached reading function that supports transparent caching of 16
  byte reads, implemented as 256 byte reads (I cannot get the A300CS to
  respond to the B1 command, but with B8 I can read 256 bytes; so I
  implemented a neat little caching layer that makes 16 byte reads
  available to the upper layers while in fact reading the larger pages
  that contain the 16 byte block and caching them for later use).
- adds support for an oceanic_atom2 open function that gets passed the
  model information, since the A300CS needs us to toggle DTR and RTS twice
  before it's willing to talk to us. The old oceanic_atom2 open function
  remains unchanged in order not to break apps that might be using it
  directly (tsk, tsk, tsk, your're not supposed to...)
- adds the necessary changes to the parser to deal with the different
  locations for various information; it supports the basics: date, time,
  duration, max depth, gasmixes plus depth, temperature and sensor
  pressure from the samples

Missing / issues:

- there is a TON more information available. Some I know where it is, but
  can't easily pass it back because of libdivecomputer architecture issues
  (e.g. the firmware version). Others are clearly there but I haven't
  figured out where (e.g. the deco state).

- the 256 byte read uses a two byte crc and I haven't been able to figure
  out the algorithm. I'm sure it's obvious and I'm just being stupid, but
  for now the check is commented out

This has been tested with Linus' new computer which has all of six dives
on it - and those six dives are rather homogeneous. This needs a lot more
testing, obviously. But so far so good - it works well from Subsurface :-)

/D


PS: Jef, I looked at the multiblock support. It adds more complexity for
    no benefit - so I decided not to add this to my patches. The reduced
    number of calls to the read function really makes no difference
    whatsoever, but the changes make the code more complex and (IMHO) more
    fragile. The caching read on the other hand is easy, straight forward,
    and reasonably obviously correct (famous last words).
-------------- next part --------------
>From 6ff8928d7a0e57a0e11f3f2e0f539fd785c69ffd Mon Sep 17 00:00:00 2001
From: Dirk Hohndel <dirk at hohndel.org>
Date: Wed, 24 Sep 2014 21:26:32 -0700
Subject: [PATCH 1/3] Prepare Oceanic infrastructure for BIGPAGE reads

Some new Oceanic dive computers like the Aeris A300CS use a different read
command that always reads 256 byte pages instead of 16 byte pages.

This patch adds a field to the oceanic_common_layout structure to indicate
which type of device this is. For bigpage type dive computers it reads big
pages and returns the small pages that the existing algorithm requests. Of
course we cache what we already read to keep things efficient.

KNOWN ISSUES: the checksum calculation for big pages is wrong. I haven't
been able to figure out which checksum algorithm is used. So for now this
is simply commented out.

Signed-off-by: Dirk Hohndel <dirk at hohndel.org>
---
 src/oceanic_atom2.c  | 108 +++++++++++++++++++++++++++++++++++++++++++--------
 src/oceanic_common.h |   3 ++
 2 files changed, 95 insertions(+), 16 deletions(-)

diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c
index 17e19580d42f..cf164ac0b1eb 100644
--- a/src/oceanic_atom2.c
+++ b/src/oceanic_atom2.c
@@ -151,6 +151,7 @@ static const oceanic_common_version_t oceanic_reactpro_version[] = {
 
 static const oceanic_common_layout_t aeris_f10_layout = {
 	0x10000, /* memsize */
+	0, /* read_big_pages */
 	0x0000, /* cf_devinfo */
 	0x0040, /* cf_pointers */
 	0x0100, /* rb_logbook_begin */
@@ -164,6 +165,7 @@ static const oceanic_common_layout_t aeris_f10_layout = {
 
 static const oceanic_common_layout_t oceanic_default_layout = {
 	0x10000, /* memsize */
+	0, /* read_big_pages */
 	0x0000, /* cf_devinfo */
 	0x0040, /* cf_pointers */
 	0x0240, /* rb_logbook_begin */
@@ -177,6 +179,7 @@ static const oceanic_common_layout_t oceanic_default_layout = {
 
 static const oceanic_common_layout_t oceanic_atom1_layout = {
 	0x8000, /* memsize */
+	0, /* read_big_pages */
 	0x0000, /* cf_devinfo */
 	0x0040, /* cf_pointers */
 	0x0240, /* rb_logbook_begin */
@@ -190,6 +193,7 @@ static const oceanic_common_layout_t oceanic_atom1_layout = {
 
 static const oceanic_common_layout_t oceanic_atom2a_layout = {
 	0xFFF0, /* memsize */
+	0, /* read_big_pages */
 	0x0000, /* cf_devinfo */
 	0x0040, /* cf_pointers */
 	0x0240, /* rb_logbook_begin */
@@ -203,6 +207,7 @@ static const oceanic_common_layout_t oceanic_atom2a_layout = {
 
 static const oceanic_common_layout_t oceanic_atom2b_layout = {
 	0x10000, /* memsize */
+	0, /* read_big_pages */
 	0x0000, /* cf_devinfo */
 	0x0040, /* cf_pointers */
 	0x0240, /* rb_logbook_begin */
@@ -216,6 +221,7 @@ static const oceanic_common_layout_t oceanic_atom2b_layout = {
 
 static const oceanic_common_layout_t oceanic_atom2c_layout = {
 	0xFFF0, /* memsize */
+	0, /* read_big_pages */
 	0x0000, /* cf_devinfo */
 	0x0040, /* cf_pointers */
 	0x0240, /* rb_logbook_begin */
@@ -229,6 +235,7 @@ static const oceanic_common_layout_t oceanic_atom2c_layout = {
 
 static const oceanic_common_layout_t tusa_zenair_layout = {
 	0xFFF0, /* memsize */
+	0, /* read_big_pages */
 	0x0000, /* cf_devinfo */
 	0x0040, /* cf_pointers */
 	0x0240, /* rb_logbook_begin */
@@ -242,6 +249,7 @@ static const oceanic_common_layout_t tusa_zenair_layout = {
 
 static const oceanic_common_layout_t oceanic_oc1_layout = {
 	0x20000, /* memsize */
+	0, /* read_big_pages */
 	0x0000, /* cf_devinfo */
 	0x0040, /* cf_pointers */
 	0x0240, /* rb_logbook_begin */
@@ -255,6 +263,7 @@ static const oceanic_common_layout_t oceanic_oc1_layout = {
 
 static const oceanic_common_layout_t oceanic_oci_layout = {
 	0x20000, /* memsize */
+	0, /* read_big_pages */
 	0x0000, /* cf_devinfo */
 	0x0040, /* cf_pointers */
 	0x10C0, /* rb_logbook_begin */
@@ -268,6 +277,7 @@ static const oceanic_common_layout_t oceanic_oci_layout = {
 
 static const oceanic_common_layout_t oceanic_atom3_layout = {
 	0x20000, /* memsize */
+	0, /* read_big_pages */
 	0x0000, /* cf_devinfo */
 	0x0040, /* cf_pointers */
 	0x0400, /* rb_logbook_begin */
@@ -281,6 +291,7 @@ static const oceanic_common_layout_t oceanic_atom3_layout = {
 
 static const oceanic_common_layout_t oceanic_vt4_layout = {
 	0x20000, /* memsize */
+	0, /* read_big_pages */
 	0x0000, /* cf_devinfo */
 	0x0040, /* cf_pointers */
 	0x0420, /* rb_logbook_begin */
@@ -294,6 +305,7 @@ static const oceanic_common_layout_t oceanic_vt4_layout = {
 
 static const oceanic_common_layout_t hollis_tx1_layout = {
 	0x40000, /* memsize */
+	0, /* read_big_pages */
 	0x0000, /* cf_devinfo */
 	0x0040, /* cf_pointers */
 	0x0780, /* rb_logbook_begin */
@@ -307,6 +319,7 @@ static const oceanic_common_layout_t hollis_tx1_layout = {
 
 static const oceanic_common_layout_t oceanic_veo1_layout = {
 	0x0400, /* memsize */
+	0, /* read_big_pages */
 	0x0000, /* cf_devinfo */
 	0x0040, /* cf_pointers */
 	0x0400, /* rb_logbook_begin */
@@ -320,6 +333,7 @@ static const oceanic_common_layout_t oceanic_veo1_layout = {
 
 static const oceanic_common_layout_t oceanic_reactpro_layout = {
 	0xFFF0, /* memsize */
+	0, /* read_big_pages */
 	0x0000, /* cf_devinfo */
 	0x0040, /* cf_pointers */
 	0x0400, /* rb_logbook_begin */
@@ -407,11 +421,22 @@ oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char comm
 		}
 
 		// Verify the checksum of the answer.
-		unsigned char crc = answer[asize - 1];
-		unsigned char ccrc = checksum_add_uint8 (answer, asize - 1, 0x00);
-		if (crc != ccrc) {
-			ERROR (abstract->context, "Unexpected answer checksum.");
-			return DC_STATUS_PROTOCOL;
+		if (asize == PAGESIZE + 1) {
+			unsigned char crc = answer[asize - 1];
+			unsigned char ccrc = checksum_add_uint8 (answer, asize - 1, 0x00);
+			if (crc != ccrc) {
+				ERROR (abstract->context, "Unexpected answer checksum.");
+				return DC_STATUS_PROTOCOL;
+			}
+		} else {
+			unsigned short crc = answer[asize - 2] << 8 + answer[asize - 1] ;
+			unsigned short ccrc = checksum_add_uint16 (answer, asize - 2, 0x00);
+			if (crc != ccrc) {
+				// this is the wrong checksum algorithm - need to figure out what they use
+//				fprintf(stderr, "checksum16 %4x %4x\n", crc, ccrc);
+//				ERROR (abstract->context, "Unexpected answer checksum.");
+//				return DC_STATUS_PROTOCOL;
+			}
 		}
 	}
 
@@ -599,37 +624,88 @@ oceanic_atom2_device_version (dc_device_t *abstract, unsigned char data[], unsig
 
 
 static dc_status_t
-oceanic_atom2_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size)
+oceanic_atom2_generic_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size, unsigned int pagesize)
 {
 	oceanic_atom2_device_t *device = (oceanic_atom2_device_t*) abstract;
+	unsigned char read_cmd = pagesize == 256 ? 0xB8 : 0xB1;
 
-	if ((address % PAGESIZE != 0) ||
-		(size    % PAGESIZE != 0))
+	if ((address % pagesize != 0) ||
+		(size    % pagesize != 0))
 		return DC_STATUS_INVALIDARGS;
 
 	unsigned int nbytes = 0;
+
 	while (nbytes < size) {
 		// Read the package.
-		unsigned int number = address / PAGESIZE;
-		unsigned char answer[PAGESIZE + 1] = {0};
-		unsigned char command[4] = {0xB1,
+		unsigned int number = address / PAGESIZE; // this is always PAGESIZE, even in BIGPAGE mode
+		unsigned char answer[BIGPAGESIZE + 2] = {0}; // big enough either way
+		unsigned int answersize = (pagesize == PAGESIZE) ? PAGESIZE + 1 : BIGPAGESIZE + 2; // 2 byte crc for BIGPAGES
+		unsigned char command[4] = {read_cmd,
 				(number >> 8) & 0xFF, // high
 				(number     ) & 0xFF, // low
 				0};
-		dc_status_t rc = oceanic_atom2_transfer (device, command, sizeof (command), answer, sizeof (answer));
+		dc_status_t rc = oceanic_atom2_transfer (device, command, sizeof (command), answer, answersize);
 		if (rc != DC_STATUS_SUCCESS)
 			return rc;
 
-		memcpy (data, answer, PAGESIZE);
+		memcpy (data, answer, pagesize);
 
-		nbytes += PAGESIZE;
-		address += PAGESIZE;
-		data += PAGESIZE;
+		nbytes += pagesize;
+		address += pagesize;
+		data += pagesize;
+	}
+
+	return DC_STATUS_SUCCESS;
+}
+
+/* instead of reading randomly in 16 byte (PAGESIZE) chunks, we read in 256 byte (16 * PAGESIZE = BIGPAGESIZE)
+ * pages and just track what has and has not been read, yet */
+static dc_status_t
+oceanic_atom2_bigpage_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size)
+{
+	oceanic_atom2_device_t *device = (oceanic_atom2_device_t*) abstract;
+	static unsigned char *tracker;
+	static unsigned char *buf;
+
+	if (!tracker) {
+		tracker = malloc(device->base.layout->memsize / BIGPAGESIZE / 8);
+		buf = malloc(device->base.layout->memsize);
+		if (!tracker || !buf)
+			return DC_STATUS_NOMEMORY;
+		memset(tracker, 0, device->base.layout->memsize / BIGPAGESIZE / 8);
 	}
+	if ((address % PAGESIZE != 0) ||
+	    (size    % PAGESIZE != 0))
+		return DC_STATUS_INVALIDARGS;
 
+	unsigned int nbytes;
+	for (nbytes = 0; nbytes < size; nbytes += PAGESIZE) {
+		/* figure out which big page this is part of and check if we have it already */
+		int idx = (address + nbytes) / (BIGPAGESIZE);
+		int bit = 1 << (idx & 0x7);
+
+		if ((tracker[idx >> 3] & bit) == 0) {
+			/* don't have that page */
+			int pageaddress = (address + nbytes) & ~(BIGPAGESIZE - 1);
+			int ret = oceanic_atom2_generic_device_read(abstract, pageaddress, buf + pageaddress, BIGPAGESIZE, BIGPAGESIZE);
+			if (ret != DC_STATUS_SUCCESS)
+				return ret;
+			tracker[idx >> 3] |=  bit;
+		}
+		memcpy(data + nbytes, buf + address + nbytes, PAGESIZE);
+	}
 	return DC_STATUS_SUCCESS;
 }
 
+static dc_status_t
+oceanic_atom2_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size)
+{
+	oceanic_atom2_device_t *device = (oceanic_atom2_device_t*) abstract;
+	if (device->base.layout->read_big_pages == 0)
+		return oceanic_atom2_generic_device_read(abstract, address, data, size, PAGESIZE);
+	else
+		return oceanic_atom2_bigpage_device_read(abstract, address, data, size);
+}
 
 static dc_status_t
 oceanic_atom2_device_write (dc_device_t *abstract, unsigned int address, const unsigned char data[], unsigned int size)
diff --git a/src/oceanic_common.h b/src/oceanic_common.h
index a9286aa4a47e..a276f1f56b5f 100644
--- a/src/oceanic_common.h
+++ b/src/oceanic_common.h
@@ -30,6 +30,7 @@ extern "C" {
 
 #define PAGESIZE 0x10
 #define FPMAXSIZE 0x20
+#define BIGPAGESIZE (PAGESIZE * 16)
 
 #define OCEANIC_COMMON_MATCH(version,patterns) \
 	oceanic_common_match ((version), (patterns), \
@@ -38,6 +39,8 @@ extern "C" {
 typedef struct oceanic_common_layout_t {
 	// Memory size.
 	unsigned int memsize;
+	// Read in 16 byte or 256 byte pages?
+	unsigned int read_big_pages;
 	// Device info.
 	unsigned int cf_devinfo;
 	// Ringbuffer pointers.
-- 
1.8.0.rc0.18.gf84667d

-------------- next part --------------
>From 6944fd9509c38315267f861b28627e9de59e7545 Mon Sep 17 00:00:00 2001
From: Dirk Hohndel <dirk at hohndel.org>
Date: Wed, 24 Sep 2014 21:39:28 -0700
Subject: [PATCH 2/3] The Aeris A300CS does not talk to USB unless DTR/RTS is
 toggled twice

This is a problem - we don't know for sure that it is an A300CS until
after the device was opened and the model data was read.

To make this work I added a new oceanic_atom2_device_open_with_model()
function that is now called from device.c (just in case someone used the
existing oceanic_atom2_device_open() call I kept that around and have it
just call into the new one with a model of -1). This allows us to do the
right thing for the A300CS.

I had to move the #defines for the various Oceanic Atom2 based dive
computers into oceanic_common.h so I would have access to the A300CS
define from the new open function.

Signed-off-by: Dirk Hohndel <dirk at hohndel.org>
---
 src/device-private.h |  3 +++
 src/device.c         |  2 +-
 src/oceanic_atom2.c  | 18 ++++++++++++++++--
 src/oceanic_common.h | 40 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 60 insertions(+), 3 deletions(-)

diff --git a/src/device-private.h b/src/device-private.h
index 8e183fb6b03e..53fa3bca99db 100644
--- a/src/device-private.h
+++ b/src/device-private.h
@@ -85,6 +85,9 @@ device_is_cancelled (dc_device_t *device);
 dc_status_t
 device_dump_read (dc_device_t *device, unsigned char data[], unsigned int size, unsigned int blocksize);
 
+dc_status_t
+oceanic_atom2_device_open_with_model (dc_device_t **out, dc_context_t *context, const char *name, int model);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff --git a/src/device.c b/src/device.c
index 9fad7a238bc4..200d883d3e0e 100644
--- a/src/device.c
+++ b/src/device.c
@@ -110,7 +110,7 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
 		rc = oceanic_veo250_device_open (&device, context, name);
 		break;
 	case DC_FAMILY_OCEANIC_ATOM2:
-		rc = oceanic_atom2_device_open (&device, context, name);
+		rc = oceanic_atom2_device_open_with_model (&device, context, name, dc_descriptor_get_model (descriptor));
 		break;
 	case DC_FAMILY_MARES_NEMO:
 		rc = mares_nemo_device_open (&device, context, name);
diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c
index cf164ac0b1eb..7ff267c15a65 100644
--- a/src/oceanic_atom2.c
+++ b/src/oceanic_atom2.c
@@ -456,9 +456,8 @@ oceanic_atom2_quit (oceanic_atom2_device_t *device)
 	return DC_STATUS_SUCCESS;
 }
 
-
 dc_status_t
-oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char *name)
+oceanic_atom2_device_open_with_model (dc_device_t **out, dc_context_t *context, const char *name, int model)
 {
 	if (out == NULL)
 		return DC_STATUS_INVALIDARGS;
@@ -487,6 +486,16 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char
 
 	// Set the serial communication protocol (38400 8N1).
 	rc = serial_configure (device->port, 38400, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE);
+
+	if (model == A300CS) {
+		// the Aeris A300CS needs these four commands to respond to the serial interface
+		// and I need to issue those before I can read the model an KNOW that it's an A300CS
+		serial_set_dtr(device->port, 1);
+		serial_set_rts(device->port, 1);
+		serial_set_dtr(device->port, 1);
+		serial_set_rts(device->port, 1);
+	}
+
 	if (rc == -1) {
 		ERROR (context, "Failed to set the terminal attributes.");
 		serial_close (device->port);
@@ -560,6 +569,11 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char
 	return DC_STATUS_SUCCESS;
 }
 
+dc_status_t
+oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char *name)
+{
+	return oceanic_atom2_device_open_with_model(out, context, name, -1);
+}
 
 static dc_status_t
 oceanic_atom2_device_close (dc_device_t *abstract)
diff --git a/src/oceanic_common.h b/src/oceanic_common.h
index a276f1f56b5f..73f6559783db 100644
--- a/src/oceanic_common.h
+++ b/src/oceanic_common.h
@@ -32,6 +32,46 @@ extern "C" {
 #define FPMAXSIZE 0x20
 #define BIGPAGESIZE (PAGESIZE * 16)
 
+#define ATOM1       0x4250
+#define EPICA       0x4257
+#define VT3         0x4258
+#define T3A         0x4259
+#define ATOM2       0x4342
+#define GEO         0x4344
+#define MANTA       0x4345
+#define DATAMASK    0x4347
+#define COMPUMASK   0x4348
+#define OC1A        0x434E
+#define F10         0x434D
+#define WISDOM2     0x4350
+#define INSIGHT2    0x4353
+#define ELEMENT2    0x4357
+#define VEO20       0x4359
+#define VEO30       0x435A
+#define ZEN         0x4441
+#define ZENAIR      0x4442
+#define ATMOSAI2    0x4443
+#define PROPLUS21   0x4444
+#define GEO20       0x4446
+#define VT4         0x4447
+#define OC1B        0x4449
+#define VOYAGER2G   0x444B
+#define ATOM3       0x444C
+#define DG03        0x444D
+#define OCS         0x4450
+#define OC1C        0x4451
+#define VT41        0x4452
+#define EPICB       0x4453
+#define T3B         0x4455
+#define ATOM31      0x4456
+#define A300AI      0x4457
+#define A300        0x445A
+#define TX1         0x4542
+#define AMPHOS      0x4545
+#define PROPLUS3    0x4548
+#define OCI         0x454B
+#define A300CS      0x454C
+
 #define OCEANIC_COMMON_MATCH(version,patterns) \
 	oceanic_common_match ((version), (patterns), \
 	sizeof (patterns) / sizeof *(patterns))
-- 
1.8.0.rc0.18.gf84667d

-------------- next part --------------
>From 48885e26d0171d5f0ee98f4adfd39abf64f41781 Mon Sep 17 00:00:00 2001
From: Dirk Hohndel <dirk at hohndel.org>
Date: Wed, 24 Sep 2014 21:42:33 -0700
Subject: [PATCH 3/3] 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.

Signed-off-by: Dirk Hohndel <dirk at hohndel.org>
---
 src/descriptor.c           |  1 +
 src/oceanic_atom2.c        | 21 +++++++++++++++++++++
 src/oceanic_atom2_parser.c | 34 +++++++++++++++++++++++++++++-----
 3 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/src/descriptor.c b/src/descriptor.c
index 403b67a8746f..617c279cc185 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 7ff267c15a65..f5b17b364b89 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 1F 2048"},
+};
+
 static const oceanic_common_layout_t aeris_f10_layout = {
 	0x10000, /* memsize */
 	0, /* read_big_pages */
@@ -345,6 +349,20 @@ static const oceanic_common_layout_t oceanic_reactpro_layout = {
 	1 /* pt_mode_logbook */
 };
 
+static const oceanic_common_layout_t aeris_a300cs_layout = {
+	0x40000, /* memsize */
+	1, /* read_big_pages */
+	0x0000, /* cf_devinfo */
+	0x0040, /* cf_pointers */
+	0x0900, /* rb_logbook_begin */
+	0x1000, /* rb_logbook_end */
+	16, /* rb_logbook_entry_size */
+	0x1000, /* rb_profile_begin */
+	0x40000, /* 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)
 {
@@ -560,6 +578,9 @@ oceanic_atom2_device_open_with_model (dc_device_t **out, dc_context_t *context,
 		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 beed0a85278b..95bd9fe850bb 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,14 @@ 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]);
+			pm = p[1] & 0x80;
+			break;
 		default:
 			datetime->year   = bcd2dec (((p[3] & 0xC0) >> 2) + (p[4] & 0x0F)) + 2000;
 			datetime->month  = (p[4] & 0xF0) >> 4;
@@ -345,7 +354,7 @@ 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)
@@ -413,7 +426,11 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
 
 	unsigned int time = 0;
 	unsigned int interval = 1;
-	if (parser->model != F10) {
+	if (parser->model == A300CS) {
+		// still need to figure this one out
+		// for now hard code
+		interval = 2;
+	} else if (parser->model != F10) {
 		switch (data[0x17] & 0x03) {
 		case 0:
 			interval = 2;
@@ -433,7 +450,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 +475,8 @@ 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);
+		int idx = parser->model == A300CS ? 16 : 2;
+		pressure = data[header + idx] + (data[header + idx + 1] << 8);
 		if (pressure == 10000)
 			have_pressure = 0;
 	}
@@ -510,6 +528,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 +573,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 +607,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.8.0.rc0.18.gf84667d



More information about the devel mailing list