Oceanic / Aeris A300CS multipage patches

Dirk Hohndel dirk at hohndel.org
Tue Oct 14 09:41:29 PDT 2014


Hi Jef,

as discussed earlier today, here are patches that implement aligned
multipage reads and mixed blocksize reads ONLY for dive computers that
support 256 byte page reads. So far that appears to be only the A300CS but
my guess is that we'll see more such dive computers in the future.

This way we should get performant downloads from the A300CS without
risking to break older dive computers.

/D
-------------- next part --------------
>From 91668d4fb82d07d59e1e6c6cc52c7ecfeaf6bf5f Mon Sep 17 00:00:00 2001
From: Dirk Hohndel <dirk at hohndel.org>
Date: Fri, 26 Sep 2014 10:58:15 -0700
Subject: [PATCH 1/6] Adjust multipage algorithm to create aligned reads for
 256 byte pages

At least the A300CS requires that 256 byte reads (16 * PAGESIZE) are
aligned to that pagesize.

Signed-off-by: Dirk Hohndel <dirk at hohndel.org>
---
 src/oceanic_common.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/oceanic_common.c b/src/oceanic_common.c
index f5f37a149596..6069157a4aaf 100644
--- a/src/oceanic_common.c
+++ b/src/oceanic_common.c
@@ -536,6 +536,16 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
 			if (nbytes + len > remaining)
 				len = remaining - nbytes; // End of profile.
 
+			// for the newer device that support reads of 16 pages, the address appears
+			// to have to be aligned
+			if (device->multipage == 16 && len == PAGESIZE * device->multipage) {
+				if (address % (PAGESIZE * device->multipage)) {
+					// this wouldn't be an aligned read
+					// let's read a smaller subset first which should have the remaining
+					// reads be aligned
+					len = address % (PAGESIZE * device->multipage);
+				}
+			}
 			// Move to the start of the current page.
 			address -= len;
 			offset -= len;
-- 
1.8.0.rc0.18.gf84667d

-------------- next part --------------
>From e750da74572b6e2a822866a09bc82a3e164975eb 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 2/6] Prepare Oceanic infrastructure for mixed multi page
 reads

Some new Oceanic dive computers like the Aeris A300CS support a new read
command that always reads 256 byte pages instead of 16 byte pages. So far
all known implementations of this command are known to support mixing and
matching different read page sizes. On the other hand, some older dive
computers that support the 128 byte pagesize read appear not to support
mixing different read page sizes. So in order not to break support for
older dive computer, this patch only implements mixing different page
sizes on dive computers that support the 256 byte pages.

This patch adds a field to the oceanic_atom2_device_t structure to
indicate which type of device this is. The multipage algorithm will
request larger, (and in the case of 256 byte reads, aligned) reads
wherever possible and fall back to standard 16 byte reads otherwise.

Signed-off-by: Dirk Hohndel <dirk at hohndel.org>
---
 src/oceanic_atom2.c | 60 +++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 47 insertions(+), 13 deletions(-)

diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c
index 17e19580d42f..aba3560b6849 100644
--- a/src/oceanic_atom2.c
+++ b/src/oceanic_atom2.c
@@ -49,6 +49,7 @@ typedef struct oceanic_atom2_device_t {
 	oceanic_common_device_t base;
 	serial_t *port;
 	unsigned int delay;
+	unsigned char bigpage;
 } oceanic_atom2_device_t;
 
 static dc_status_t oceanic_atom2_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size);
@@ -406,9 +407,15 @@ oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char comm
 			return EXITCODE (n);
 		}
 
-		// Verify the checksum of the answer.
-		unsigned char crc = answer[asize - 1];
-		unsigned char ccrc = checksum_add_uint8 (answer, asize - 1, 0x00);
+		// Verify the checksum of the answer; we can use unsigned short in both cases
+		unsigned short crc, ccrc;
+		if (asize == 256 + 2) { // 256 byte pages get two crc bytes
+			crc = (answer[asize - 1] << 8) | answer[asize - 2] ;
+			ccrc = checksum_add_uint16 (answer, asize - 2, 0x0000);
+		} else {
+			crc = answer[asize - 1];
+			ccrc = checksum_add_uint8 (answer, asize - 1, 0x00);
+		}
 		if (crc != ccrc) {
 			ERROR (abstract->context, "Unexpected answer checksum.");
 			return DC_STATUS_PROTOCOL;
@@ -451,6 +458,7 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char
 	// Set the default values.
 	device->port = NULL;
 	device->delay = 0;
+	device->bigpage = 1; // no big pages
 
 	// Open the device.
 	int rc = serial_open (&device->port, context, name);
@@ -598,33 +606,59 @@ oceanic_atom2_device_version (dc_device_t *abstract, unsigned char data[], unsig
 }
 
 
+/* newer devices like the A300CS allow switching between different page sizes between reads across
+ * the whole address space - but some older devices have problems when doing that. In order not to
+ * break support for older dive computers, we only support mixed block sized for models that support
+ * bigpages consisting of 16 PAGES (like the A300CS). In that case, if we have aligned reads of a
+ * larger pagesize use the larger block reads, otherwise just loop and read in PAGESIZE chunks */
 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 ((address % PAGESIZE != 0) ||
-		(size    % PAGESIZE != 0))
+	// pick the best pagesize to use
+	unsigned int pagesize = PAGESIZE;
+
+	if (device->bigpage == 16 && size == 16 * PAGESIZE && address % (16 * PAGESIZE) == 0)
+		pagesize = 16 * PAGESIZE;
+
+	// pick the correct read command and number of crc bytes based on the page size
+	unsigned char read_cmd, crc_size;
+	if (pagesize == 16 * PAGESIZE) {
+		read_cmd = 0xB8;
+		crc_size = 2;
+	} else if (pagesize == 8 * PAGESIZE) {
+		read_cmd = 0xB4;
+		crc_size = 1;
+	} else {
+		read_cmd = 0xB1;
+		crc_size = 1;
+	}
+
+	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[256 + 2] = {0};           // maximum we support for the known commands
+		unsigned int answersize = pagesize + crc_size;
+		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;
-- 
1.8.0.rc0.18.gf84667d



More information about the devel mailing list