Aeris A300CS patches [V2]

Dirk Hohndel dirk at hohndel.org
Fri Sep 26 11:19:35 PDT 2014


Jef,

I think I have taken all of your feedback into account.

On Fri, Sep 26, 2014 at 09:52:05AM +0200, Jef Driesen wrote:
> 
> We don't have to use the existing multipage support. I just wanted to check
> whether we can re-use the existing infrastructure before adding something
> completely new. If it turns out your caching is a better solution, then fine
> no problem.

I figured out why the multipage support didn't work for me. It doesn't
create aligned reads - but the A300CS only works with aligned reads. Not
sure about the other models that support this feature, but the patch
series enclosed includes one commit that fixes the oceanic common layer to
make those multipage calls page aligned and suddenly this becomes more
useful.

Granted, it STILL doesn't save any reads from the device (the caching made
sure that every page was only read once), but it at least now is more
efficient.

I kept the caching in order to avoid multiple reads when the common layer
calls for unaligned reads or smaller reads than the multipage size.

If you really worry about the caching code then yes, we could not include
it (on my current download that would create about 30 additional reads of
pages that we already read before).

>  * You used global variables for the cache and its bitmap. That's simply not
> acceptable. Please move this into the device handle. (I suggest you use the
> name "bitmap" instead of "tracker". In the ostc backend we already used
> "bitmap" for the exact same purpose.) And then you can pre-allocate
> everything in the open function.

Fixed.

>  * Remove the read_big_pages from the layout. The layout is intended for the
> logic in the shared oceanic_common_device_xxx functions. But didn't change
> anything there. You actually introduced a bug in the vtpro and veo250
> backends, because their layouts were not updated with the new field. So
> instead add some "bigpage" field directly to the device handle.

Fixed.

>  * There are some other devices like the OC1 that also support the newer B4
> command. But they appear to use 128 byte packets (8 pages) instead of 256
> byte packets (16 pages). So I would prefer that BIGPAGESIZE isn't hardcoded.
> That will make it easier to adapt it to other devices if needed. For example
> by setting the "bigpage" field above to 0 to disable the bigpage feature,
> and to 8 (OC1) or 16 (A300CS). I don't think such a change really affects
> your caching logic.

Fixed (but I did not enable this for any other devices as I can't test
it... the code is all there)

>  * Libdivecomputer uses unsigned integers everywhere, especially if bit
> manipulations are involved.

Fixed.

>  * For the checksum function. Just a crazy idea, but you never know. Maybe
> it's not a 256 byte packet with a 2 byte checksum. But two times a 128 byte
> packet with a 1 byte checksum? That means all your second halves shift one
> byte, and you would probably notice some problems during parsing, but you
> never know. The reason why I think this might be a possibility is that the
> OC1 seemed to use such 128 byte packets with a 1 byte checksum. Most likely
> I'm just wrong here, but it's worth checking.

It was indeed the 16bit add function. I had tried that, but I had messed
up the assembly of the crc data in the buffer (:facepalm:) and that's why
I thought this wasn't the right answer...

>  * Setting DTR/RTS twice looks really odd. Are you sure this is really
> needed? Does the Aeris application does this too? (Note that due to how the
> win32 api works, DTR/RTS are automatically set when configuring the line
> settings, but there are also separate calls for DTR/RTS.) For other devices
> I noticed that setting DTR/RTS may require a small delay after opening the
> serial port. So maybe you are just not doing it at the right time. Try to
> move it after that 100ms sleep.

This is now just two calls (instead of doing those two calls twice) and
done unconditional for all Atom2 devices (which of course needs to be
tested). This simplified the code quite a bit.

>  * I don't see the different baudrate anywhere in the patches. Did you
> forgot to include that part?

See previous comment - this isn't needed.

>  * In the aeris_a300cs_version string, mask the firmware version with
> "\0\0". Otherwise it will only work for one firmware version.

Fixed.

Let me know if we are getting closer or if there are more parts you want
me to rework (e.g. the cache code).

/D
-------------- next part --------------
>From f4def2a0b4a53f456bc9c8b53fc3bfe933279dfa 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/4] Prepare Oceanic infrastructure for multi page 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, other
versions support reading 128 byte pages.

This patch adds three fields to the oceanic_atom2_device_t structure to
indicate which type of device this is and to hold a cache and
corresponding bitmap to track the device reads. For divecomputers that
support the larger pagesizes it reads big pages and returns 16 byte
sub-pages that the existing algorithm requests, while caching the data for
sub-sequent reads of other sub-pages.

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

diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c
index 17e19580d42f..48ea4b2e390b 100644
--- a/src/oceanic_atom2.c
+++ b/src/oceanic_atom2.c
@@ -49,6 +49,10 @@ typedef struct oceanic_atom2_device_t {
 	oceanic_common_device_t base;
 	serial_t *port;
 	unsigned int delay;
+	unsigned char *bitmap;
+	unsigned char *cache;
+	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 +410,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 +461,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);
@@ -599,37 +610,98 @@ 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)
 {
 	oceanic_atom2_device_t *device = (oceanic_atom2_device_t*) abstract;
-
-	if ((address % PAGESIZE != 0) ||
-		(size    % PAGESIZE != 0))
+	unsigned int pagesize = device->bigpage * 16;
+
+	// pick the correct read command and number of crc bytes based on the page size
+	unsigned char read_cmd, crc_size;
+	if (pagesize == 256) {
+		read_cmd = 0xB8;
+		crc_size = 2;
+	} else if (pagesize == 128) {
+		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;
 }
 
+/* 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;
+	unsigned int pagesize = PAGESIZE * device->bigpage;
+	if (!device->bitmap) {
+		device->bitmap = malloc(device->base.layout->memsize / pagesize / 8);
+		device->cache = malloc(device->base.layout->memsize);
+		if (!device->bitmap || !device->cache)
+			return DC_STATUS_NOMEMORY;
+		memset(device->bitmap, 0, device->base.layout->memsize / pagesize / 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 */
+		unsigned int idx = (address + nbytes) / (pagesize);
+		unsigned char bit = 1 << (idx & 0x7);
+
+		if ((device->bitmap[idx >> 3] & bit) == 0) {
+			/* don't have that page */
+			unsigned int pageaddress = (address + nbytes) & ~(pagesize - 1);
+			int ret = oceanic_atom2_generic_device_read(abstract, pageaddress, device->cache + pageaddress, pagesize);
+			if (ret != DC_STATUS_SUCCESS)
+				return ret;
+			device->bitmap[idx >> 3] |=  bit;
+		}
+		memcpy(data + nbytes, device->cache + 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->bigpage == 1)
+		return oceanic_atom2_generic_device_read(abstract, address, data, size);
+	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)
-- 
1.8.0.rc0.18.gf84667d

-------------- next part --------------
>From cf23362acfbd7595aec7d9e0536c8ccb4d50c3e1 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/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.

TODO:
- we need to verify that this doesn't cause any issues with earlier models.
- interval is hard coded - need to figure out where this is encoded

Signed-off-by: Dirk Hohndel <dirk at hohndel.org>
---
 src/descriptor.c           |  1 +
 src/oceanic_atom2.c        | 28 ++++++++++++++++++++++++++--
 src/oceanic_atom2_parser.c | 34 +++++++++++++++++++++++++++++-----
 3 files changed, 56 insertions(+), 7 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 48ea4b2e390b..0fa1996d1b4c 100644
--- a/src/oceanic_atom2.c
+++ b/src/oceanic_atom2.c
@@ -153,6 +153,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 */
@@ -335,6 +339,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 */
+	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)
 {
@@ -472,8 +489,7 @@ 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 (rc == -1) {
+	if (serial_configure (device->port, 38400, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE) == -1) {
 		ERROR (context, "Failed to set the terminal attributes.");
 		serial_close (device->port);
 		free (device);
@@ -491,6 +507,11 @@ 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);
 
+	// at least the Aeris A300CS needs these two commands to respond to the serial interface
+	// need to verify that these don't cause problem with earlier models
+	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);
 
@@ -537,6 +558,9 @@ 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;
+		device->bigpage = 16;
 	} 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

-------------- next part --------------
>From 181ac15c638d4b805697afc2868e253de6bc5760 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 3/4] Fix multipage algorithm to create aligned reads

At least the A300CS requires that reads are aligned to the pagesize that
is read.

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

diff --git a/src/oceanic_common.c b/src/oceanic_common.c
index f5f37a149596..d5313d563eb7 100644
--- a/src/oceanic_common.c
+++ b/src/oceanic_common.c
@@ -536,6 +536,15 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac
 			if (nbytes + len > remaining)
 				len = remaining - nbytes; // End of profile.
 
+			// if we are able to read multiple pages, make sure we have an aligned address
+			if (device->multipage > 1 && 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 fd50b614793fc1b73fb9632d303fd71df1ff577a Mon Sep 17 00:00:00 2001
From: Dirk Hohndel <dirk at hohndel.org>
Date: Fri, 26 Sep 2014 11:02:12 -0700
Subject: [PATCH 4/4] Enable multipage support for the A300CS

This optimizes the algorithm for page aligned reads of big pages. With the
previous commit the oceanic common layer gives us such reads which makes
the code slightly faster.

Thanks to the caching this doesn't actually reduce the total number of
reads from the device, but it still seems like the right thing to do.

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

diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c
index 0fa1996d1b4c..27b4e5c010fa 100644
--- a/src/oceanic_atom2.c
+++ b/src/oceanic_atom2.c
@@ -561,6 +561,7 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char
 	} else if (OCEANIC_COMMON_MATCH (device->base.version, aeris_a300cs_version)) {
 		device->base.layout = &aeris_a300cs_layout;
 		device->bigpage = 16;
+		device->base.multipage = 16;
 	} else {
 		device->base.layout = &oceanic_default_layout;
 	}
@@ -680,13 +681,22 @@ oceanic_atom2_generic_device_read (dc_device_t *abstract, unsigned int address,
 	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)
 {
+	/* if we have an aligned read of exactly the device's page size (which the multipage algorithm in
+	 * oceanic_common should give us most of the time) just read that, otherwise read the enclosing
+	 * larger page(s) and copy what is needed into data */
 	oceanic_atom2_device_t *device = (oceanic_atom2_device_t*) abstract;
 	unsigned int pagesize = PAGESIZE * device->bigpage;
+
+	if (size == pagesize && address % pagesize == 0) {
+		// excellent, multipage did its job
+		return oceanic_atom2_generic_device_read(abstract, address, data, pagesize);
+	}
+
+	/* for the smaller reads we want to cache things */
 	if (!device->bitmap) {
 		device->bitmap = malloc(device->base.layout->memsize / pagesize / 8);
 		device->cache = malloc(device->base.layout->memsize);
@@ -694,6 +704,7 @@ oceanic_atom2_bigpage_device_read (dc_device_t *abstract, unsigned int address,
 			return DC_STATUS_NOMEMORY;
 		memset(device->bitmap, 0, device->base.layout->memsize / pagesize / 8);
 	}
+
 	if ((address % PAGESIZE != 0) ||
 	    (size    % PAGESIZE != 0))
 		return DC_STATUS_INVALIDARGS;
-- 
1.8.0.rc0.18.gf84667d



More information about the devel mailing list