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); } }