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.
This commit is contained in:
parent
4c37c9c85f
commit
1e39b84075
@ -19,28 +19,66 @@
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h> // malloc
|
||||
#include <string.h> // memcpy, memcmp
|
||||
#include <assert.h> // 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;
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user