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