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