diff --git a/src/cressi_edy.c b/src/cressi_edy.c index 4ac6b90..78a052a 100644 --- a/src/cressi_edy.c +++ b/src/cressi_edy.c @@ -29,29 +29,44 @@ #include "utils.h" #include "checksum.h" #include "array.h" +#include "ringbuffer.h" #define EXITCODE(rc) \ ( \ rc == -1 ? DEVICE_STATUS_IO : DEVICE_STATUS_TIMEOUT \ ) +#define PAGESIZE (CRESSI_EDY_PACKET_SIZE / 4) + +#define BASE 0x4000 + +#define RB_PROFILE_BEGIN 0x4000 +#define RB_PROFILE_END 0x7F80 + +#define RB_LOGBOOK_OFFSET 0x7F80 +#define RB_LOGBOOK_BEGIN 0 +#define RB_LOGBOOK_END 60 + typedef struct cressi_edy_device_t { device_t base; struct serial *port; + unsigned char fingerprint[PAGESIZE / 2]; } cressi_edy_device_t; +static device_status_t cressi_edy_device_set_fingerprint (device_t *abstract, const unsigned char data[], unsigned int size); static device_status_t cressi_edy_device_read (device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); static device_status_t cressi_edy_device_dump (device_t *abstract, dc_buffer_t *buffer); +static device_status_t cressi_edy_device_foreach (device_t *abstract, dive_callback_t callback, void *userdata); static device_status_t cressi_edy_device_close (device_t *abstract); static const device_backend_t cressi_edy_device_backend = { DEVICE_TYPE_CRESSI_EDY, - NULL, /* set_fingerprint */ + cressi_edy_device_set_fingerprint, /* set_fingerprint */ NULL, /* version */ cressi_edy_device_read, /* read */ NULL, /* write */ cressi_edy_device_dump, /* dump */ - NULL, /* foreach */ + cressi_edy_device_foreach, /* foreach */ cressi_edy_device_close /* close */ }; @@ -281,6 +296,23 @@ cressi_edy_device_read (device_t *abstract, unsigned int address, unsigned char } +static device_status_t +cressi_edy_device_set_fingerprint (device_t *abstract, const unsigned char data[], unsigned int size) +{ + cressi_edy_device_t *device = (cressi_edy_device_t *) abstract; + + 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; +} + + static device_status_t cressi_edy_device_dump (device_t *abstract, dc_buffer_t *buffer) { @@ -297,3 +329,99 @@ cressi_edy_device_dump (device_t *abstract, dc_buffer_t *buffer) return device_dump_read (abstract, dc_buffer_get_data (buffer), dc_buffer_get_size (buffer), CRESSI_EDY_PACKET_SIZE); } + + +static device_status_t +cressi_edy_device_foreach (device_t *abstract, dive_callback_t callback, void *userdata) +{ + cressi_edy_device_t *device = (cressi_edy_device_t *) abstract; + + // Enable progress notifications. + device_progress_t progress = DEVICE_PROGRESS_INITIALIZER; + progress.maximum = CRESSI_EDY_PACKET_SIZE + + (RB_PROFILE_END - RB_PROFILE_BEGIN); + device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress); + + // Read the configuration data. + unsigned char config[CRESSI_EDY_PACKET_SIZE] = {0}; + device_status_t rc = cressi_edy_device_read (abstract, 0x7F80, config, sizeof (config)); + if (rc != DEVICE_STATUS_SUCCESS) { + WARNING ("Failed to read the configuration data."); + return rc; + } + + // Update and emit a progress event. + progress.current += CRESSI_EDY_PACKET_SIZE; + device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress); + + // Get the logbook pointers. + unsigned int last = config[0x7C]; + unsigned int first = config[0x7D]; + + // Get the number of logbook items. + unsigned int count = ringbuffer_distance (first, last, 0, RB_LOGBOOK_BEGIN, RB_LOGBOOK_END) + 1; + + // Get the profile pointer. + unsigned int eop = array_uint16_le (config + 0x7E) * PAGESIZE + BASE; + + // Memory buffer for the profile data. + unsigned char buffer[RB_PROFILE_END - RB_PROFILE_BEGIN] = {0}; + + unsigned int available = 0; + unsigned int offset = RB_PROFILE_END - RB_PROFILE_BEGIN; + + unsigned int previous = eop; + unsigned int address = previous; + + unsigned int idx = last; + for (unsigned int i = 0; i < count; ++i) { + // Get the pointer to the profile data. + unsigned int current = array_uint16_le (config + 2 * idx) * PAGESIZE + BASE; + + // Position the pointer at the start of the header. + if (current == RB_PROFILE_BEGIN) + current = RB_PROFILE_END; + current -= PAGESIZE; + + // Get the profile length. + unsigned int length = ringbuffer_distance (current, previous, 1, RB_PROFILE_BEGIN, RB_PROFILE_END); + + unsigned nbytes = available; + while (nbytes < length) { + if (address == RB_PROFILE_BEGIN) + address = RB_PROFILE_END; + address -= CRESSI_EDY_PACKET_SIZE; + offset -= CRESSI_EDY_PACKET_SIZE; + + // Read the memory page. + rc = cressi_edy_device_read (abstract, address, buffer + offset, CRESSI_EDY_PACKET_SIZE); + if (rc != DEVICE_STATUS_SUCCESS) { + WARNING ("Failed to read the memory page."); + return rc; + } + + // Update and emit a progress event. + progress.current += CRESSI_EDY_PACKET_SIZE; + device_event_emit (abstract, DEVICE_EVENT_PROGRESS, &progress); + + nbytes += CRESSI_EDY_PACKET_SIZE; + } + + available = nbytes - length; + previous = current; + + unsigned char *p = buffer + offset + available; + + if (memcmp (p, device->fingerprint, sizeof (device->fingerprint)) == 0) + return DEVICE_STATUS_SUCCESS; + + if (callback && !callback (p, length, p, sizeof (device->fingerprint), userdata)) + return DEVICE_STATUS_SUCCESS; + + if (idx == RB_LOGBOOK_BEGIN) + idx = RB_LOGBOOK_END; + idx--; + } + + return DEVICE_STATUS_SUCCESS; +}