diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index a808dde..99d6dc0 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -56,6 +56,7 @@ reefnet_sensusultra_extract_dives suunto_d9_device_open suunto_d9_device_reset_maxdepth suunto_solution_device_open +suunto_solution_extract_dives suunto_eon_device_open suunto_eon_device_write_interval suunto_eon_device_write_name diff --git a/src/suunto_solution.c b/src/suunto_solution.c index 54b54f8..bc0f5e3 100644 --- a/src/suunto_solution.c +++ b/src/suunto_solution.c @@ -20,9 +20,11 @@ */ #include // malloc, free +#include // assert #include "device-private.h" #include "suunto_solution.h" +#include "ringbuffer.h" #include "serial.h" #include "utils.h" @@ -36,6 +38,9 @@ rc == -1 ? DEVICE_STATUS_IO : DEVICE_STATUS_TIMEOUT \ ) +#define RB_PROFILE_BEGIN 0x020 +#define RB_PROFILE_END 0x100 + typedef struct suunto_solution_device_t suunto_solution_device_t; struct suunto_solution_device_t { @@ -44,6 +49,7 @@ struct suunto_solution_device_t { }; static device_status_t suunto_solution_device_dump (device_t *abstract, unsigned char data[], unsigned int size, unsigned int *result); +static device_status_t suunto_solution_device_foreach (device_t *abstract, dive_callback_t callback, void *userdata); static device_status_t suunto_solution_device_close (device_t *abstract); static const device_backend_t suunto_solution_device_backend = { @@ -53,7 +59,7 @@ static const device_backend_t suunto_solution_device_backend = { NULL, /* read */ NULL, /* write */ suunto_solution_device_dump, /* dump */ - NULL, /* foreach */ + suunto_solution_device_foreach, /* foreach */ suunto_solution_device_close /* close */ }; @@ -228,3 +234,72 @@ suunto_solution_device_dump (device_t *abstract, unsigned char data[], unsigned return DEVICE_STATUS_SUCCESS; } + + +static device_status_t +suunto_solution_device_foreach (device_t *abstract, dive_callback_t callback, void *userdata) +{ + if (! device_is_suunto_solution (abstract)) + return DEVICE_STATUS_TYPE_MISMATCH; + + unsigned char data[SUUNTO_SOLUTION_MEMORY_SIZE] = {0}; + + device_status_t rc = suunto_solution_device_dump (abstract, data, sizeof (data), NULL); + if (rc != DEVICE_STATUS_SUCCESS) + return rc; + + return suunto_solution_extract_dives (data, sizeof (data), callback, userdata); +} + + +device_status_t +suunto_solution_extract_dives (const unsigned char data[], unsigned int size, dive_callback_t callback, void *userdata) +{ + assert (size >= SUUNTO_SOLUTION_MEMORY_SIZE); + + unsigned char buffer[RB_PROFILE_END - RB_PROFILE_BEGIN] = {0}; + + // Get the end of the profile ring buffer. + unsigned int eop = data[0x18]; + assert (eop >= RB_PROFILE_BEGIN && eop < RB_PROFILE_END); + assert (data[eop] == 0x82); + + // The profile data is stored backwards in the ringbuffer. To locate + // the most recent dive, we start from the end of profile marker and + // traverse the ringbuffer in the opposite direction (forwards). + // Since the profile data is now processed in the "wrong" direction, + // it needs to be reversed again. + unsigned int previous = eop; + unsigned int current = eop; + for (unsigned int i = 0; i < RB_PROFILE_END - RB_PROFILE_BEGIN; ++i) { + // Move forwards through the ringbuffer. + current++; + if (current == RB_PROFILE_END) + current = RB_PROFILE_BEGIN; + + // Check for an end of profile marker. + if (data[current] == 0x82) + break; + + // Store the current byte into the buffer. By starting at the + // end of the buffer, the data is automatically reversed. + unsigned int idx = RB_PROFILE_END - RB_PROFILE_BEGIN - i - 1; + buffer[idx] = data[current]; + + // Check for an end of dive marker (of the next dive), + // to find the start of the current dive. + unsigned int peek = ringbuffer_increment (current, 2, RB_PROFILE_BEGIN, RB_PROFILE_END); + if (data[peek] == 0x80) { + unsigned int len = ringbuffer_distance (previous, current, RB_PROFILE_BEGIN, RB_PROFILE_END); + + if (callback && !callback (buffer + idx, len, userdata)) + return DEVICE_STATUS_SUCCESS; + + previous = current; + } + } + + assert (data[current] == 0x82); + + return DEVICE_STATUS_SUCCESS; +} diff --git a/src/suunto_solution.h b/src/suunto_solution.h index 87c6e16..a58fb0a 100644 --- a/src/suunto_solution.h +++ b/src/suunto_solution.h @@ -33,6 +33,9 @@ extern "C" { device_status_t suunto_solution_device_open (device_t **device, const char* name); +device_status_t +suunto_solution_extract_dives (const unsigned char data[], unsigned int size, dive_callback_t callback, void *userdata); + #ifdef __cplusplus } #endif /* __cplusplus */