>From 6ff8928d7a0e57a0e11f3f2e0f539fd785c69ffd Mon Sep 17 00:00:00 2001 From: Dirk Hohndel 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 --- 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