Skip to content

Commit

Permalink
Implement some missing features for the Cressi Edy.
Browse files Browse the repository at this point in the history
The internal memory appears to contain two separate areas. One for the
normal dives and one for the freedives. Currently, only the freedive
section is processed.
  • Loading branch information
jefdriesen committed May 3, 2010
1 parent 996bfb2 commit 60249d0
Showing 1 changed file with 130 additions and 2 deletions.
132 changes: 130 additions & 2 deletions src/cressi_edy.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
};

Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
}

0 comments on commit 60249d0

Please sign in to comment.