From 1e39b840754624f29ec2914c06388956013dcedc Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 12 May 2009 19:57:46 +0000 Subject: [PATCH] Add a common base class and a layout descriptor structure. The memory layout of the Suunto Eon and Vyper devices is very similar, which allows to share the parsing code between the backends. Differences in the layout are passed by means of a new layout descriptor structure and a common base class is introduced to share the fingerprint data. Memory buffers are now allocated dynamically to support devices with different amounts of memory. --- src/suunto_common.c | 78 +++++++++++++++++++++++++++++++++++---------- src/suunto_common.h | 25 +++++++++++++-- src/suunto_eon.c | 48 ++++++++++++---------------- src/suunto_vyper.c | 73 ++++++++++++++++++------------------------ 4 files changed, 134 insertions(+), 90 deletions(-) diff --git a/src/suunto_common.c b/src/suunto_common.c index 7f58923..ff2fdb8 100644 --- a/src/suunto_common.c +++ b/src/suunto_common.c @@ -19,28 +19,66 @@ * MA 02110-1301 USA */ -#include -#include +#include // malloc +#include // memcpy, memcmp +#include // assert #include "suunto_common.h" #include "ringbuffer.h" +#define RB_PROFILE_DISTANCE(a,b,l) ringbuffer_distance (a, b, l->rb_profile_begin, l->rb_profile_end) +#define RB_PROFILE_PEEK(a,l) ringbuffer_decrement (a, l->peek, l->rb_profile_begin, l->rb_profile_end) + +void +suunto_common_device_init (suunto_common_device_t *device, const device_backend_t *backend) +{ + assert (device != NULL); + + // Initialize the base class. + device_init (&device->base, backend); + + // Set the default values. + memset (device->fingerprint, 0, sizeof (device->fingerprint)); +} + device_status_t -suunto_common_extract_dives (device_t *device, const unsigned char data[], unsigned int begin, unsigned int end, unsigned int eop, unsigned int peek, fp_compare_t fp_compare, dive_callback_t callback, void *userdata) +suunto_common_device_set_fingerprint (suunto_common_device_t *device, const unsigned char data[], unsigned int size) { - assert (eop >= begin && eop < end); + assert (device != NULL); + + if (size && size != sizeof (device->fingerprint)) + return DEVICE_STATUS_ERROR; + + if (size) + memcpy (device->fingerprint, data, sizeof (device->fingerprint)); + else + memset (device->fingerprint, 0, sizeof (device->fingerprint)); + + return DEVICE_STATUS_SUCCESS; +} + + +device_status_t +suunto_common_extract_dives (suunto_common_device_t *device, const suunto_common_layout_t *layout, const unsigned char data[], unsigned int eop, dive_callback_t callback, void *userdata) +{ + assert (layout != NULL); + + assert (eop >= layout->rb_profile_begin && eop < layout->rb_profile_end); assert (data[eop] == 0x82); - unsigned char buffer[0x2000 - 0x4C] = {0}; - assert (sizeof (buffer) >= end - begin); + // Memory buffer for the profile ringbuffer. + unsigned int length = layout->rb_profile_end - layout->rb_profile_begin; + unsigned char *buffer = (unsigned char *) malloc (length); + if (buffer == NULL) + return DEVICE_STATUS_MEMORY; unsigned int current = eop; unsigned int previous = eop; - for (unsigned int i = 0; i < end - begin; ++i) { + for (unsigned int i = 0; i < length; ++i) { // Move backwards through the ringbuffer. - if (current == begin) - current = end; + if (current == layout->rb_profile_begin) + current = layout->rb_profile_end; current--; // Check for an end of profile marker. @@ -49,28 +87,34 @@ suunto_common_extract_dives (device_t *device, const unsigned char data[], unsig // Check for an end of dive marker (of the next dive), // to find the start of the current dive. - unsigned int idx = ringbuffer_decrement (current, peek, begin, end); + unsigned int idx = RB_PROFILE_PEEK (current, layout); if (data[idx] == 0x80) { - unsigned int len = ringbuffer_distance (current, previous, begin, end); - if (current + len > end) { - unsigned int a = end - current; - unsigned int b = (current + len) - end; + unsigned int len = RB_PROFILE_DISTANCE (current, previous, layout); + if (current + len > layout->rb_profile_end) { + unsigned int a = layout->rb_profile_end - current; + unsigned int b = (current + len) - layout->rb_profile_end; memcpy (buffer + 0, data + current, a); - memcpy (buffer + a, data + begin, b); + memcpy (buffer + a, data + layout->rb_profile_begin, b); } else { memcpy (buffer, data + current, len); } - if (device && fp_compare && fp_compare (device, buffer, len) == 0) + if (device && memcmp (buffer + layout->fp_offset, device->fingerprint, sizeof (device->fingerprint)) == 0) { + free (buffer); return DEVICE_STATUS_SUCCESS; + } - if (callback && !callback (buffer, len, userdata)) + if (callback && !callback (buffer, len, userdata)) { + free (buffer); return DEVICE_STATUS_SUCCESS; + } previous = current; } } + free (buffer); + assert (data[current] == 0x82); return DEVICE_STATUS_SUCCESS; diff --git a/src/suunto_common.h b/src/suunto_common.h index 0bc279c..063bf06 100644 --- a/src/suunto_common.h +++ b/src/suunto_common.h @@ -22,16 +22,35 @@ #ifndef SUUNTO_COMMON_H #define SUUNTO_COMMON_H -#include "device.h" +#include "device-private.h" #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -typedef int (*fp_compare_t) (device_t *device, const unsigned char data[], unsigned int size); +typedef struct suunto_common_device_t { + device_t base; + unsigned char fingerprint[5]; +} suunto_common_device_t; + +typedef struct suunto_common_layout_t { + // Profile ringbuffer + unsigned int rb_profile_begin; + unsigned int rb_profile_end; + // Fingerprint + unsigned int fp_offset; + // Peek + unsigned int peek; +} suunto_common_layout_t; + +void +suunto_common_device_init (suunto_common_device_t *device, const device_backend_t *backend); device_status_t -suunto_common_extract_dives (device_t *device, const unsigned char data[], unsigned int begin, unsigned int end, unsigned int eop, unsigned int peek, fp_compare_t fp_compare, dive_callback_t callback, void *userdata); +suunto_common_device_set_fingerprint (suunto_common_device_t *device, const unsigned char data[], unsigned int size); + +device_status_t +suunto_common_extract_dives (suunto_common_device_t *device, const suunto_common_layout_t *layout, const unsigned char data[], unsigned int eop, dive_callback_t callback, void *userdata); #ifdef __cplusplus } diff --git a/src/suunto_eon.c b/src/suunto_eon.c index df0a2e0..4ecc0ed 100644 --- a/src/suunto_eon.c +++ b/src/suunto_eon.c @@ -41,13 +41,9 @@ rc == -1 ? DEVICE_STATUS_IO : DEVICE_STATUS_TIMEOUT \ ) -#define FP_OFFSET 6 -#define FP_SIZE 5 - typedef struct suunto_eon_device_t { - device_t base; + suunto_common_device_t base; struct serial *port; - unsigned char fingerprint[FP_SIZE]; } suunto_eon_device_t; static device_status_t suunto_eon_device_set_fingerprint (device_t *abstract, const unsigned char data[], unsigned int size); @@ -66,6 +62,14 @@ static const device_backend_t suunto_eon_device_backend = { suunto_eon_device_close /* close */ }; +static const suunto_common_layout_t suunto_eon_layout = { + 0x100, /* rb_profile_begin */ + SUUNTO_EON_MEMORY_SIZE, /* rb_profile_end */ + 6, /* fp_offset */ + 3 /* peek */ +}; + + static int device_is_suunto_eon (device_t *abstract) { @@ -90,11 +94,10 @@ suunto_eon_device_open (device_t **out, const char* name) } // Initialize the base class. - device_init (&device->base, &suunto_eon_device_backend); + suunto_common_device_init (&device->base, &suunto_eon_device_backend); // Set the default values. device->port = NULL; - memset (device->fingerprint, 0, FP_SIZE); // Open the device. int rc = serial_open (&device->port, name); @@ -159,20 +162,12 @@ suunto_eon_device_close (device_t *abstract) static device_status_t suunto_eon_device_set_fingerprint (device_t *abstract, const unsigned char data[], unsigned int size) { - suunto_eon_device_t *device = (suunto_eon_device_t*) abstract; + suunto_common_device_t *device = (suunto_common_device_t*) abstract; if (! device_is_suunto_eon (abstract)) return DEVICE_STATUS_TYPE_MISMATCH; - if (size && size != FP_SIZE) - return DEVICE_STATUS_ERROR; - - if (size) - memcpy (device->fingerprint, data, FP_SIZE); - else - memset (device->fingerprint, 0, FP_SIZE); - - return DEVICE_STATUS_SUCCESS; + return suunto_common_device_set_fingerprint (device, data, size); } @@ -295,19 +290,16 @@ suunto_eon_device_write_interval (device_t *abstract, unsigned char interval) } -static int -fp_compare (device_t *abstract, const unsigned char data[], unsigned int size) -{ - suunto_eon_device_t *device = (suunto_eon_device_t*) abstract; - - return memcmp (data + FP_OFFSET, device->fingerprint, FP_SIZE); -} - - device_status_t suunto_eon_extract_dives (device_t *abstract, const unsigned char data[], unsigned int size, dive_callback_t callback, void *userdata) { - assert (size >= SUUNTO_EON_MEMORY_SIZE); + suunto_common_device_t *device = (suunto_common_device_t*) abstract; + + if (abstract && !device_is_suunto_eon (abstract)) + return DEVICE_STATUS_TYPE_MISMATCH; + + if (size < SUUNTO_EON_MEMORY_SIZE) + return DEVICE_STATUS_ERROR; // Search the end-of-profile marker. unsigned int eop = 0x100; @@ -318,5 +310,5 @@ suunto_eon_extract_dives (device_t *abstract, const unsigned char data[], unsign eop++; } - return suunto_common_extract_dives (abstract, data, 0x100, SUUNTO_EON_MEMORY_SIZE, eop, 3, fp_compare, callback, userdata); + return suunto_common_extract_dives (device, &suunto_eon_layout, data, eop, callback, userdata); } diff --git a/src/suunto_vyper.c b/src/suunto_vyper.c index 789a57f..98b35b6 100644 --- a/src/suunto_vyper.c +++ b/src/suunto_vyper.c @@ -44,15 +44,10 @@ #define HDR_DEVINFO_BEGIN (HDR_DEVINFO_SPYDER) #define HDR_DEVINFO_END (HDR_DEVINFO_VYPER + 6) -#define FP_OFFSET_VYPER 9 -#define FP_OFFSET_SPYDER 7 -#define FP_SIZE 5 - typedef struct suunto_vyper_device_t { - device_t base; + suunto_common_device_t base; struct serial *port; unsigned int delay; - unsigned char fingerprint[FP_SIZE]; } suunto_vyper_device_t; static device_status_t suunto_vyper_device_set_fingerprint (device_t *abstract, const unsigned char data[], unsigned int size); @@ -73,6 +68,21 @@ static const device_backend_t suunto_vyper_device_backend = { suunto_vyper_device_close /* close */ }; +static const suunto_common_layout_t suunto_vyper_layout = { + 0x71, /* rb_profile_begin */ + SUUNTO_VYPER_MEMORY_SIZE, /* rb_profile_end */ + 9, /* fp_offset */ + 5 /* peek */ +}; + +static const suunto_common_layout_t suunto_spyder_layout = { + 0x4C, /* rb_profile_begin */ + SUUNTO_VYPER_MEMORY_SIZE, /* rb_profile_end */ + 7, /* fp_offset */ + 3 /* peek */ +}; + + static int device_is_suunto_vyper (device_t *abstract) { @@ -97,12 +107,11 @@ suunto_vyper_device_open (device_t **out, const char* name) } // Initialize the base class. - device_init (&device->base, &suunto_vyper_device_backend); + suunto_common_device_init (&device->base, &suunto_vyper_device_backend); // Set the default values. device->port = NULL; device->delay = 500; - memset (device->fingerprint, 0, FP_SIZE); // Open the device. int rc = serial_open (&device->port, name); @@ -187,20 +196,12 @@ suunto_vyper_device_set_delay (device_t *abstract, unsigned int delay) static device_status_t suunto_vyper_device_set_fingerprint (device_t *abstract, const unsigned char data[], unsigned int size) { - suunto_vyper_device_t *device = (suunto_vyper_device_t*) abstract; + suunto_common_device_t *device = (suunto_common_device_t*) abstract; if (! device_is_suunto_vyper (abstract)) return DEVICE_STATUS_TYPE_MISMATCH; - if (size && size != FP_SIZE) - return DEVICE_STATUS_ERROR; - - if (size) - memcpy (device->fingerprint, data, FP_SIZE); - else - memset (device->fingerprint, 0, FP_SIZE); - - return DEVICE_STATUS_SUCCESS; + return suunto_common_device_set_fingerprint (device, data, size); } @@ -561,7 +562,7 @@ suunto_vyper_device_dump (device_t *abstract, unsigned char data[], unsigned int static device_status_t suunto_vyper_device_foreach (device_t *abstract, dive_callback_t callback, void *userdata) { - suunto_vyper_device_t *device = (suunto_vyper_device_t*) abstract; + suunto_common_device_t *device = (suunto_common_device_t*) abstract; if (! device_is_suunto_vyper (abstract)) return DEVICE_STATUS_TYPE_MISMATCH; @@ -618,8 +619,8 @@ suunto_vyper_device_foreach (device_t *abstract, dive_callback_t callback, void if (nbytes == 0) return DEVICE_STATUS_SUCCESS; - unsigned int fp_offset = (vyper ? FP_OFFSET_VYPER : FP_OFFSET_SPYDER); - if (memcmp (data + offset + fp_offset, device->fingerprint, FP_SIZE) == 0) + unsigned int fp_offset = (vyper ? suunto_vyper_layout.fp_offset : suunto_spyder_layout.fp_offset); + if (memcmp (data + offset + fp_offset, device->fingerprint, sizeof (device->fingerprint)) == 0) return DEVICE_STATUS_SUCCESS; if (callback && !callback (data + offset, nbytes, userdata)) @@ -633,28 +634,16 @@ suunto_vyper_device_foreach (device_t *abstract, dive_callback_t callback, void } -static int -fp_compare_vyper (device_t *abstract, const unsigned char data[], unsigned int size) -{ - suunto_vyper_device_t *device = (suunto_vyper_device_t*) abstract; - - return memcmp (data + FP_OFFSET_VYPER, device->fingerprint, FP_SIZE); -} - - -static int -fp_compare_spyder (device_t *abstract, const unsigned char data[], unsigned int size) -{ - suunto_vyper_device_t *device = (suunto_vyper_device_t*) abstract; - - return memcmp (data + FP_OFFSET_SPYDER, device->fingerprint, FP_SIZE); -} - - device_status_t suunto_vyper_extract_dives (device_t *abstract, const unsigned char data[], unsigned int size, dive_callback_t callback, void *userdata) { - assert (size >= SUUNTO_VYPER_MEMORY_SIZE); + suunto_common_device_t *device = (suunto_common_device_t*) abstract; + + if (abstract && !device_is_suunto_vyper (abstract)) + return DEVICE_STATUS_TYPE_MISMATCH; + + if (size < SUUNTO_VYPER_MEMORY_SIZE) + return DEVICE_STATUS_ERROR; unsigned int vyper = 1; if (data[HDR_DEVINFO_VYPER] == 20 || data[HDR_DEVINFO_VYPER] == 30 || data[HDR_DEVINFO_VYPER] == 60) @@ -662,9 +651,9 @@ suunto_vyper_extract_dives (device_t *abstract, const unsigned char data[], unsi if (vyper) { unsigned int eop = array_uint16_be (data + 0x51); - return suunto_common_extract_dives (abstract, data, 0x71, SUUNTO_VYPER_MEMORY_SIZE, eop, 5, fp_compare_vyper, callback, userdata); + return suunto_common_extract_dives (device, &suunto_vyper_layout, data, eop, callback, userdata); } else { unsigned int eop = array_uint16_be (data + 0x1C); - return suunto_common_extract_dives (abstract, data, 0x4C, SUUNTO_VYPER_MEMORY_SIZE, eop, 3, fp_compare_spyder, callback, userdata); + return suunto_common_extract_dives (device, &suunto_spyder_layout, data, eop, callback, userdata); } }