diff --git a/suunto_common.c b/suunto_common.c new file mode 100644 index 0000000..136bb96 --- /dev/null +++ b/suunto_common.c @@ -0,0 +1,74 @@ +#include +#include + +#include "suunto_common.h" + +#define SUBSTRACT(a, x, begin, end) substract (a - begin, x, end - begin) + begin +#define DISTANCE(a, b, begin, end) distance (a, b, end - begin) + +static unsigned int +substract (unsigned int a, unsigned int x, unsigned int size) +{ + if (x <= a) { + return (a - x) % size; + } else { + return size - (x - a) % size; + } +} + +static unsigned int +distance (unsigned int a, unsigned int b, unsigned int size) +{ + if (a <= b) { + return (b - a) % size; + } else { + return size - (a - b) % size; + } +} + +int +suunto_common_extract_dives (const unsigned char data[], unsigned int begin, unsigned int end, unsigned int eop, unsigned int peek, dive_callback_t callback, void *userdata) +{ + assert (eop >= begin && eop < end); + assert (data[eop] == 0x82); + + unsigned char buffer[0x2000 - 0x4C] = {0}; + assert (sizeof (buffer) >= end - begin); + + unsigned int current = eop; + unsigned int previous = eop; + for (unsigned int i = 0; i < end - begin; ++i) { + // Move backwards through the ringbuffer. + if (current == begin) + current = end; + current--; + + // Check for an end of profile marker. + if (data[current] == 0x82) + break; + + // Check for an end of dive marker (of the next dive), + // to find the start of the current dive. + unsigned int peek = SUBSTRACT (current, peek, begin, end); + if (data[peek] == 0x80) { + unsigned int len = DISTANCE (current, previous, begin, end); + if (current + len > end) { + unsigned int a = end - current; + unsigned int b = (current + len) - end; + memcpy (buffer + 0, data + current, a); + memcpy (buffer + a, data + begin, b); + } else { + memcpy (buffer, data + current, len); + } + + if (callback) + callback (buffer, len, userdata); + + previous = current; + } + } + + assert (data[current] == 0x82); + + return SUUNTO_SUCCESS; +} diff --git a/suunto_common.h b/suunto_common.h new file mode 100644 index 0000000..6d223dc --- /dev/null +++ b/suunto_common.h @@ -0,0 +1,15 @@ +#ifndef SUUNTO_COMMON_H +#define SUUNTO_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "suunto.h" + +int suunto_common_extract_dives (const unsigned char data[], unsigned int begin, unsigned int end, unsigned int eop, unsigned int peek, dive_callback_t callback, void *userdata); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* SUUNTO_COMMON_H */ diff --git a/suunto_eon.c b/suunto_eon.c index 733a67d..0d5a416 100644 --- a/suunto_eon.c +++ b/suunto_eon.c @@ -1,7 +1,9 @@ #include // memcmp, memcpy #include // malloc, free +#include // assert #include "suunto.h" +#include "suunto_common.h" #include "serial.h" #include "utils.h" @@ -184,3 +186,21 @@ suunto_eon_write_interval (eon *device, unsigned char interval) return SUUNTO_SUCCESS; } + + +int +suunto_eon_extract_dives (const unsigned char data[], unsigned int size, dive_callback_t callback, void *userdata) +{ + assert (size >= SUUNTO_EON_MEMORY_SIZE); + + // Search the end-of-profile marker. + unsigned int eop = 0x100; + while (eop < SUUNTO_EON_MEMORY_SIZE) { + if (data[eop] == 0x82) { + break; + } + eop++; + } + + return suunto_common_extract_dives (data, 0x100, SUUNTO_EON_MEMORY_SIZE, eop, 3, callback, userdata); +} diff --git a/suunto_eon.h b/suunto_eon.h index 9457a01..77e3fd4 100644 --- a/suunto_eon.h +++ b/suunto_eon.h @@ -19,6 +19,8 @@ int suunto_eon_write_name (eon *device, unsigned char data[], unsigned int size) int suunto_eon_write_interval (eon *device, unsigned char interval); +int suunto_eon_extract_dives (const unsigned char data[], unsigned int size, dive_callback_t callback, void *userdata); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/suunto_vyper.c b/suunto_vyper.c index 9273ea7..0a404c2 100644 --- a/suunto_vyper.c +++ b/suunto_vyper.c @@ -3,6 +3,7 @@ #include // assert #include "suunto.h" +#include "suunto_common.h" #include "serial.h" #include "utils.h" @@ -533,3 +534,25 @@ suunto_vyper_read_dives (vyper *device, dive_callback_t callback, void *userdata return SUUNTO_SUCCESS; } + + +int +suunto_vyper_extract_dives (const unsigned char data[], unsigned int size, dive_callback_t callback, void *userdata) +{ + assert (size >= SUUNTO_VYPER_MEMORY_SIZE); + + unsigned int eop = (data[0x51] << 8) + data[0x52]; + + return suunto_common_extract_dives (data, 0x71, SUUNTO_VYPER_MEMORY_SIZE, eop, 5, callback, userdata); +} + + +int +suunto_spyder_extract_dives (const unsigned char data[], unsigned int size, dive_callback_t callback, void *userdata) +{ + assert (size >= SUUNTO_VYPER_MEMORY_SIZE); + + unsigned int eop = (data[0x1C] << 8) + data[0x1D]; + + return suunto_common_extract_dives (data, 0x4C, SUUNTO_VYPER_MEMORY_SIZE, eop, 3, callback, userdata); +} diff --git a/suunto_vyper.h b/suunto_vyper.h index 659baf1..cd1abcf 100644 --- a/suunto_vyper.h +++ b/suunto_vyper.h @@ -26,6 +26,10 @@ int suunto_vyper_write_memory (vyper *device, unsigned int address, const unsign int suunto_vyper_read_dives (vyper *device, dive_callback_t callback, void *userdata); +int suunto_vyper_extract_dives (const unsigned char data[], unsigned int size, dive_callback_t callback, void *userdata); + +int suunto_spyder_extract_dives (const unsigned char data[], unsigned int size, dive_callback_t callback, void *userdata); + #ifdef __cplusplus } #endif /* __cplusplus */