From 4fa0f4cc59c59a56ed390080dc236b38adb346cc Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 24 Sep 2014 21:26:32 -0700 Subject: [PATCH 1/6] Prepare Oceanic infrastructure for 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, other versions support reading 128 byte pages. This patch adds a field to the oceanic_atom2_device_t structure to indicate which type of device this is. If bigpage mode is enabled, the algorithm will always request larger, aligned reads and fall back to standard 16 byte reads otherwise. Signed-off-by: Dirk Hohndel --- src/oceanic_atom2.c | 67 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 17e1958..80639db 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 int 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); @@ -369,7 +370,7 @@ oceanic_atom2_send (oceanic_atom2_device_t *device, const unsigned char command[ static dc_status_t -oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) +oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int crc_size) { dc_device_t *abstract = (dc_device_t *) device; @@ -407,8 +408,14 @@ 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); + unsigned short crc, ccrc; + if (crc_size == 2) { + crc = array_uint16_le (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); @@ -567,7 +575,7 @@ oceanic_atom2_device_keepalive (dc_device_t *abstract) // Send the command to the dive computer. unsigned char command[4] = {0x91, 0x05, 0xA5, 0x00}; - dc_status_t rc = oceanic_atom2_transfer (device, command, sizeof (command), NULL, 0); + dc_status_t rc = oceanic_atom2_transfer (device, command, sizeof (command), NULL, 0, 0); if (rc != DC_STATUS_SUCCESS) return rc; @@ -588,7 +596,7 @@ oceanic_atom2_device_version (dc_device_t *abstract, unsigned char data[], unsig unsigned char answer[PAGESIZE + 1] = {0}; unsigned char command[2] = {0x84, 0x00}; - 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, sizeof (answer), 1); if (rc != DC_STATUS_SUCCESS) return rc; @@ -607,24 +615,53 @@ oceanic_atom2_device_read (dc_device_t *abstract, unsigned int address, unsigned (size % PAGESIZE != 0)) return DC_STATUS_INVALIDARGS; + // Pick the correct read command and number of checksum bytes. + unsigned char read_cmd = 0x00; + unsigned int crc_size = 0; + switch (device->bigpage) { + case 1: + read_cmd = 0xB1; + crc_size = 1; + break; + case 8: + read_cmd = 0xB4; + crc_size = 1; + break; + case 16: + read_cmd = 0xB8; + crc_size = 2; + break; + default: + return DC_STATUS_INVALIDARGS; + } + + // Pick the best pagesize to use. + unsigned int pagesize = device->bigpage * PAGESIZE; + 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 page = address / pagesize; + unsigned int number = page * device->bigpage; // This is always PAGESIZE, even in big page mode. + unsigned char answer[256 + 2] = {0}; // Maximum we support for the known commands. + 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, pagesize + crc_size, crc_size); if (rc != DC_STATUS_SUCCESS) return rc; - memcpy (data, answer, PAGESIZE); + unsigned int offset = address % pagesize; + unsigned int length = pagesize - offset; + if (nbytes + length > size) + length = size - nbytes; - nbytes += PAGESIZE; - address += PAGESIZE; - data += PAGESIZE; + memcpy (data, answer + offset, length); + + nbytes += length; + address += length; + data += length; } return DC_STATUS_SUCCESS; @@ -648,7 +685,7 @@ oceanic_atom2_device_write (dc_device_t *abstract, unsigned int address, const u (number >> 8) & 0xFF, // high (number ) & 0xFF, // low 0x00}; - dc_status_t rc = oceanic_atom2_transfer (device, prepare, sizeof (prepare), NULL, 0); + dc_status_t rc = oceanic_atom2_transfer (device, prepare, sizeof (prepare), NULL, 0, 0); if (rc != DC_STATUS_SUCCESS) return rc; @@ -656,7 +693,7 @@ oceanic_atom2_device_write (dc_device_t *abstract, unsigned int address, const u unsigned char command[PAGESIZE + 2] = {0}; memcpy (command, data, PAGESIZE); command[PAGESIZE] = checksum_add_uint8 (command, PAGESIZE, 0x00); - rc = oceanic_atom2_transfer (device, command, sizeof (command), NULL, 0); + rc = oceanic_atom2_transfer (device, command, sizeof (command), NULL, 0, 0); if (rc != DC_STATUS_SUCCESS) return rc; From d89dd952c9f601ce1be2b93bbad250e72506fea7 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 24 Sep 2014 21:39:28 -0700 Subject: [PATCH 2/6] 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. Signed-off-by: Dirk Hohndel --- src/descriptor.c | 1 + src/oceanic_atom2.c | 24 ++++++++++++++++++++++++ src/oceanic_atom2_parser.c | 35 ++++++++++++++++++++++++++++++----- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/descriptor.c b/src/descriptor.c index 403b67a..617c279 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 80639db..2606be7 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -150,6 +150,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 */ @@ -332,6 +336,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 */ + 0x3FE00, /* 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) { @@ -488,6 +505,10 @@ 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); + // Set the DTR/RTS lines. + 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); @@ -534,6 +555,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 423c5a5..8afa6ea 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,13 @@ 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]); + break; default: datetime->year = bcd2dec (((p[3] & 0xC0) >> 2) + (p[4] & 0x0F)) + 2000; datetime->month = (p[4] & 0xF0) >> 4; @@ -346,7 +354,8 @@ 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; @@ -358,6 +367,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]; @@ -404,6 +415,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) @@ -415,7 +428,10 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ unsigned int time = 0; unsigned int interval = 1; if (parser->model != F10) { - switch (data[0x17] & 0x03) { + unsigned int idx = 0x17; + if (parser->model == A300CS) + idx = 0x1f; + switch (data[idx] & 0x03) { case 0: interval = 2; break; @@ -434,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; @@ -459,7 +475,10 @@ 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); + unsigned int idx = 2; + if (parser->model == A300CS) + idx = 16; + pressure = data[header + idx] + (data[header + idx + 1] << 8); if (pressure == 10000) have_pressure = 0; } @@ -511,6 +530,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; @@ -552,6 +575,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) @@ -584,7 +609,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]; From 16fb1c18695acbd3ee442cbba1f7ab44a236a975 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Tue, 30 Sep 2014 12:35:04 -0700 Subject: [PATCH 3/6] Aeris A300CS: add support for NDL / deco data Encoded in every sample. The depth is in multiples of 10 feet which gives somewhat odd metric stop depth - but rounding to full meters would take care of that. Signed-off-by: Dirk Hohndel --- src/oceanic_atom2_parser.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 8afa6ea..3abbae0 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -634,6 +634,22 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ sample.depth = depth / 16.0 * FEET; if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata); + // NDL / Deco + // bits 6..4 of byte 15 encode deco state & depth + // bytes 6 & 7 encode minutes of NDL / deco + if (parser->model == A300CS) { + unsigned int deco = (data[offset + 15] & 0x70) >> 4; + if (deco) { + sample.deco.type = DC_DECO_DECOSTOP; + sample.deco.depth = deco * 10 * FEET; + } else { + sample.deco.type = DC_DECO_NDL; + sample.deco.depth = 0.0; + } + sample.deco.time = array_uint16_le(data + offset + 6) & 0x03FF; + if (callback) callback (DC_SAMPLE_DECO, sample, userdata); + } + complete = 1; } From 7a108f555bc541a5343bbf6635c0181a208930ef Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Wed, 1 Oct 2014 15:28:37 -0700 Subject: [PATCH 4/6] Aeris A300CS: add reporting of water type (fresh/salt) Signed-off-by: Dirk Hohndel --- src/oceanic_atom2_parser.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 3abbae0..6983be7 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -333,6 +333,7 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns } dc_gasmix_t *gasmix = (dc_gasmix_t *) value; + dc_salinity_t *water = (dc_salinity_t *) value; unsigned int oxygen = 0; unsigned int helium = 0; @@ -379,6 +380,18 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns gasmix->oxygen = (oxygen ? oxygen / 100.0 : 0.21); gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; break; + case DC_FIELD_SALINITY: + if (parser->model == A300CS) { + if (data[0x18] & 0x80) { + water->type = DC_WATER_FRESH; + } else { + water->type = DC_WATER_SALT; + } + water->density = 0.0; + } else { + return DC_STATUS_UNSUPPORTED; + } + break; default: return DC_STATUS_UNSUPPORTED; } From 0bcee519e0463b877efc5b69bc19697080d8646c Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Thu, 2 Oct 2014 10:47:57 -0700 Subject: [PATCH 5/6] Aeris A300CS: detect the number of cylinders used The A300CS actually tells us how many of the cylinders it considers "in use". Signed-off-by: Dirk Hohndel --- src/oceanic_atom2_parser.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 6983be7..8dedf3f 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -353,15 +353,26 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns *((double *) value) = array_uint16_le (data + footer + 4) / 16.0 * FEET; break; case DC_FIELD_GASMIX_COUNT: - if (parser->model == DATAMASK || parser->model == COMPUMASK) + if (parser->model == DATAMASK || parser->model == COMPUMASK) { *((unsigned int *) value) = 1; - else if (parser->model == VT4 || parser->model == VT41 || - parser->model == OCI || parser->model == A300CS) + } else if (parser->model == VT4 || parser->model == VT41 || + parser->model == OCI) { *((unsigned int *) value) = 4; - else if (parser->model == TX1) + } else if (parser->model == TX1) { *((unsigned int *) value) = 6; - else + } else if (parser->model == A300CS) { + if (data[0x39] & 0x04) { + *((unsigned int *) value) = 1; + } else if (data[0x39] & 0x08) { + *((unsigned int *) value) = 2; + } else if (data[0x39] & 0x10) { + *((unsigned int *) value) = 3; + } else { + *((unsigned int *) value) = 4; + } + } else { *((unsigned int *) value) = 3; + } break; case DC_FIELD_GASMIX: if (parser->model == DATAMASK || parser->model == COMPUMASK) { From a1ff11e08e184f38efbcb60e2b00a279ea3a9726 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 26 Oct 2014 17:29:58 +0100 Subject: [PATCH 6/6] Cache the last page to reduce the number of I/O operations. In bigpage mode, we always read large pages, regardless of the amount of bytes requested by the caller. Excess bytes are simply discarded. This is inefficient because the same large page will be downloaded multiple times, when requesting more than one 16 byte page from the same large page. By caching the pages internally, we can greatly reduce the amount of I/O operations. In practice, applications and also libdivecomputer's internal algorithm for downloading the dives will typically request contiguous pages, so we only need to cache the last page. This implementation is based on ideas and code contributed by Dirk Hohndel. --- src/oceanic_atom2.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 2606be7..733c547 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -36,6 +36,7 @@ #define MAXRETRIES 2 #define MAXDELAY 16 +#define INVALID 0xFFFFFFFF #define EXITCODE(rc) \ ( \ @@ -50,6 +51,8 @@ typedef struct oceanic_atom2_device_t { serial_t *port; unsigned int delay; unsigned int bigpage; + unsigned char cache[256]; + unsigned int cached; } 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); @@ -476,6 +479,8 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, const char device->port = NULL; device->delay = 0; device->bigpage = 1; // no big pages + device->cached = INVALID; + memset(device->cache, 0, sizeof(device->cache)); // Open the device. int rc = serial_open (&device->port, context, name); @@ -664,24 +669,30 @@ oceanic_atom2_device_read (dc_device_t *abstract, unsigned int address, unsigned unsigned int nbytes = 0; while (nbytes < size) { - // Read the package. unsigned int page = address / pagesize; - unsigned int number = page * device->bigpage; // This is always PAGESIZE, even in big page mode. - unsigned char answer[256 + 2] = {0}; // Maximum we support for the known commands. - 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, pagesize + crc_size, crc_size); - if (rc != DC_STATUS_SUCCESS) - return rc; + if (page != device->cached) { + // Read the package. + unsigned int number = page * device->bigpage; // This is always PAGESIZE, even in big page mode. + unsigned char answer[256 + 2] = {0}; // Maximum we support for the known commands. + 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, pagesize + crc_size, crc_size); + if (rc != DC_STATUS_SUCCESS) + return rc; + + // Cache the page. + memcpy (device->cache, answer, pagesize); + device->cached = page; + } unsigned int offset = address % pagesize; unsigned int length = pagesize - offset; if (nbytes + length > size) length = size - nbytes; - memcpy (data, answer + offset, length); + memcpy (data, device->cache + offset, length); nbytes += length; address += length; @@ -701,6 +712,9 @@ oceanic_atom2_device_write (dc_device_t *abstract, unsigned int address, const u (size % PAGESIZE != 0)) return DC_STATUS_INVALIDARGS; + // Invalidate the cache. + device->cached = INVALID; + unsigned int nbytes = 0; while (nbytes < size) { // Prepare to write the package.