From 2a0defe30da1ffeea06951b848b5f2b01b357881 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Fri, 7 Oct 2011 22:02:54 +0200 Subject: [PATCH] Adjust the total amount of memory for the newer Suunto's. The D9tx, D6i and D4i have twice the amount of memory compared to the previous versions (64K versus 32K). To support both variants, a new layout descriptor is introduced. --- src/suunto_common2.c | 65 ++++++++++++++++++++++++++++---------------- src/suunto_common2.h | 11 ++++++++ src/suunto_d9.c | 21 ++++++++++++++ src/suunto_vyper2.c | 10 +++++++ 4 files changed, 83 insertions(+), 24 deletions(-) diff --git a/src/suunto_common2.c b/src/suunto_common2.c index cb3f1b1..543f9b0 100644 --- a/src/suunto_common2.c +++ b/src/suunto_common2.c @@ -19,6 +19,7 @@ * MA 02110-1301 USA */ +#include // malloc #include // memcmp, memcpy #include // assert @@ -28,22 +29,15 @@ #include "checksum.h" #include "array.h" -#define D4i 0x19 -#define D6i 0x1A -#define D9tx 0x1B - #define MAXRETRIES 2 #define SZ_VERSION 0x04 -#define SZ_MEMORY 0x8000 #define SZ_PACKET 0x78 #define SZ_MINIMUM 8 #define FP_OFFSET 0x15 -#define RB_PROFILE_BEGIN 0x019A -#define RB_PROFILE_END SZ_MEMORY - 2 -#define RB_PROFILE_DISTANCE(a,b,m) ringbuffer_distance (a, b, m, RB_PROFILE_BEGIN, RB_PROFILE_END) +#define RB_PROFILE_DISTANCE(l,a,b,m) ringbuffer_distance (a, b, m, l->rb_profile_begin, l->rb_profile_end) #define BACKEND(abstract) ((suunto_common2_device_backend_t *) abstract->backend) @@ -56,6 +50,7 @@ suunto_common2_device_init (suunto_common2_device_t *device, const suunto_common device_init (&device->base, &backend->base); // Set the default values. + device->layout = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); } @@ -214,9 +209,14 @@ suunto_common2_device_write (device_t *abstract, unsigned int address, const uns device_status_t suunto_common2_device_dump (device_t *abstract, dc_buffer_t *buffer) { + suunto_common2_device_t *device = (suunto_common2_device_t *) abstract; + + assert (device != NULL); + assert (device->layout != NULL); + // Erase the current contents of the buffer and // allocate the required amount of memory. - if (!dc_buffer_clear (buffer) || !dc_buffer_resize (buffer, SZ_MEMORY)) { + if (!dc_buffer_clear (buffer) || !dc_buffer_resize (buffer, device->layout->memsize)) { WARNING ("Insufficient buffer space available."); return DEVICE_STATUS_MEMORY; } @@ -231,9 +231,15 @@ suunto_common2_device_foreach (device_t *abstract, dive_callback_t callback, voi { suunto_common2_device_t *device = (suunto_common2_device_t*) abstract; + assert (device != NULL); + assert (device->layout != NULL); + + const suunto_common2_layout_t *layout = device->layout; + // Enable progress notifications. device_progress_t progress = DEVICE_PROGRESS_INITIALIZER; - progress.maximum = RB_PROFILE_END - RB_PROFILE_BEGIN + 8 + SZ_VERSION + (SZ_MINIMUM > 4 ? SZ_MINIMUM : 4); + progress.maximum = layout->rb_profile_end - layout->rb_profile_begin + + 8 + SZ_VERSION + (SZ_MINIMUM > 4 ? SZ_MINIMUM : 4); device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress); // Read the version info. @@ -249,11 +255,8 @@ suunto_common2_device_foreach (device_t *abstract, dive_callback_t callback, voi device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress); // Read the serial number. - unsigned int addr = 0x0023; - if (version[0] == D4i || version[0] == D6i || version[0] == D9tx) - addr++; unsigned char serial[SZ_MINIMUM > 4 ? SZ_MINIMUM : 4] = {0}; - rc = suunto_common2_device_read (abstract, addr, serial, sizeof (serial)); + rc = suunto_common2_device_read (abstract, layout->serial, serial, sizeof (serial)); if (rc != DEVICE_STATUS_SUCCESS) { WARNING ("Cannot read memory header."); return rc; @@ -286,15 +289,19 @@ suunto_common2_device_foreach (device_t *abstract, dive_callback_t callback, voi // Memory buffer to store all the dives. - unsigned char data[SZ_MINIMUM + RB_PROFILE_END - RB_PROFILE_BEGIN] = {0}; + unsigned char *data = (unsigned char *) malloc (layout->rb_profile_end - layout->rb_profile_begin + SZ_MINIMUM); + if (data == NULL) { + WARNING ("Failed to allocate memory."); + return DEVICE_STATUS_MEMORY; + } // Calculate the total amount of bytes. - unsigned int remaining = RB_PROFILE_DISTANCE (begin, end, count != 0); + unsigned int remaining = RB_PROFILE_DISTANCE (layout, begin, end, count != 0); // Update and emit a progress event. - progress.maximum -= (RB_PROFILE_END - RB_PROFILE_BEGIN) - remaining; + progress.maximum -= (layout->rb_profile_end - layout->rb_profile_begin) - remaining; progress.current += sizeof (header); device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress); @@ -315,24 +322,26 @@ suunto_common2_device_foreach (device_t *abstract, dive_callback_t callback, voi unsigned int offset = remaining + SZ_MINIMUM; while (remaining) { // Calculate the size of the current dive. - unsigned int size = RB_PROFILE_DISTANCE (current, previous, 1); + unsigned int size = RB_PROFILE_DISTANCE (layout, current, previous, 1); + if (size < 4 || size > remaining) { WARNING ("Unexpected profile size."); + free (data); return DEVICE_STATUS_ERROR; } unsigned int nbytes = available; while (nbytes < size) { // Handle the ringbuffer wrap point. - if (address == RB_PROFILE_BEGIN) - address = RB_PROFILE_END; + if (address == layout->rb_profile_begin) + address = layout->rb_profile_end; // Calculate the package size. Try with the largest possible // size first, and adjust when the end of the ringbuffer or // the end of the profile data is reached. unsigned int len = SZ_PACKET; - if (RB_PROFILE_BEGIN + len > address) - len = address - RB_PROFILE_BEGIN; // End of ringbuffer. + if (layout->rb_profile_begin + len > address) + len = address - layout->rb_profile_begin; // End of ringbuffer. if (nbytes + len > remaining) len = remaining - nbytes; // End of profile. /*if (nbytes + len > size) @@ -354,6 +363,7 @@ suunto_common2_device_foreach (device_t *abstract, dive_callback_t callback, voi rc = suunto_common2_device_read (abstract, address - extra, data + offset - extra, len + extra); if (rc != DEVICE_STATUS_SUCCESS) { WARNING ("Cannot read memory."); + free (data); return rc; } @@ -377,6 +387,7 @@ suunto_common2_device_foreach (device_t *abstract, dive_callback_t callback, voi unsigned int next = array_uint16_le (p + 2); if (next != previous) { WARNING ("Profiles are not continuous."); + free (data); return DEVICE_STATUS_ERROR; } @@ -388,12 +399,18 @@ suunto_common2_device_foreach (device_t *abstract, dive_callback_t callback, voi if (devinfo.model == 0x15) fp_offset += 6; // HelO2 - if (memcmp (p + fp_offset, device->fingerprint, sizeof (device->fingerprint)) == 0) + if (memcmp (p + fp_offset, device->fingerprint, sizeof (device->fingerprint)) == 0) { + free (data); return DEVICE_STATUS_SUCCESS; + } - if (callback && !callback (p + 4, size - 4, p + fp_offset, sizeof (device->fingerprint), userdata)) + if (callback && !callback (p + 4, size - 4, p + fp_offset, sizeof (device->fingerprint), userdata)) { + free (data); return DEVICE_STATUS_SUCCESS; + } } + free (data); + return DEVICE_STATUS_SUCCESS; } diff --git a/src/suunto_common2.h b/src/suunto_common2.h index 52b8f9a..1ffc5fc 100644 --- a/src/suunto_common2.h +++ b/src/suunto_common2.h @@ -28,8 +28,19 @@ extern "C" { #endif /* __cplusplus */ +typedef struct suunto_common2_layout_t { + // Memory size. + unsigned int memsize; + // Serial number. + unsigned int serial; + // Profile ringbuffer + unsigned int rb_profile_begin; + unsigned int rb_profile_end; +} suunto_common2_layout_t; + typedef struct suunto_common2_device_t { device_t base; + const suunto_common2_layout_t *layout; unsigned char fingerprint[7]; } suunto_common2_device_t; diff --git a/src/suunto_d9.c b/src/suunto_d9.c index 297ecc7..b8cc021 100644 --- a/src/suunto_d9.c +++ b/src/suunto_d9.c @@ -64,6 +64,20 @@ static const suunto_common2_device_backend_t suunto_d9_device_backend = { suunto_d9_device_packet }; +static const suunto_common2_layout_t suunto_d9_layout = { + 0x8000, /* memsize */ + 0x0023, /* serial */ + 0x019A, /* rb_profile_begin */ + 0x7FFE /* rb_profile_end */ +}; + +static const suunto_common2_layout_t suunto_d9tx_layout = { + 0x10000, /* memsize */ + 0x0024, /* serial */ + 0x019A, /* rb_profile_begin */ + 0xFFFE /* rb_profile_end */ +}; + static int device_is_suunto_d9 (device_t *abstract) { @@ -176,6 +190,13 @@ suunto_d9_device_open (device_t **out, const char* name) return status; } + // Override the base class values. + unsigned int model = device->version[0]; + if (model == D4i || model == D6i || model == D9tx) + device->base.layout = &suunto_d9tx_layout; + else + device->base.layout = &suunto_d9_layout; + *out = (device_t*) device; return DEVICE_STATUS_SUCCESS; diff --git a/src/suunto_vyper2.c b/src/suunto_vyper2.c index 7560087..06cbd6b 100644 --- a/src/suunto_vyper2.c +++ b/src/suunto_vyper2.c @@ -56,6 +56,13 @@ static const suunto_common2_device_backend_t suunto_vyper2_device_backend = { suunto_vyper2_device_packet }; +static const suunto_common2_layout_t suunto_vyper2_layout = { + 0x8000, /* memsize */ + 0x0023, /* serial */ + 0x019A, /* rb_profile_begin */ + 0x7FFE /* rb_profile_end */ +}; + static int device_is_suunto_vyper2 (device_t *abstract) { @@ -124,6 +131,9 @@ suunto_vyper2_device_open (device_t **out, const char* name) // Make sure everything is in a sane state. serial_flush (device->port, SERIAL_QUEUE_BOTH); + // Override the base class values. + device->base.layout = &suunto_vyper2_layout; + *out = (device_t*) device; return DEVICE_STATUS_SUCCESS;