Implement some missing features for the Cressi Edy.

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.
This commit is contained in:
Jef Driesen 2010-05-03 18:02:23 +00:00
parent 996bfb2b48
commit 60249d075d

View File

@ -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;
}