From 3d3c3f60398ae9da5f437f38f70c8dd8df4762a7 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sat, 15 Dec 2012 20:25:16 +0100 Subject: [PATCH] Add support for the Mares Nemo Wide 2. The Nemo Wide 2 uses the same communication protocol as the Icon HD, except for two differences: The Nemo Wide 2 requires a different baudrate and parity setting. Unfortunately it doesn't seem possible to autodetect the correct protocol variant at runtime. Attempting to proceed with incorrect settings will render the device unresponsive and requires a battery reset to recover.Therefore the model code needs to be provided as an extra parameter, when opening the connection. The Nemo Wide 2 also appears to have trouble downloading the entire memory with a single request. Therefore the single large request is split into many smaller ones. The offical Mares application uses 256 byte packets, and so do we. The Icon HD keeps using the large packets because they are significant faster. The extra model parameter breaks backwards compatibility! --- examples/mares_iconhd_test.c | 15 +++-- include/libdivecomputer/mares_iconhd.h | 2 +- src/descriptor.c | 1 + src/device.c | 2 +- src/mares_iconhd.c | 84 +++++++++++++++++--------- 5 files changed, 70 insertions(+), 34 deletions(-) diff --git a/examples/mares_iconhd_test.c b/examples/mares_iconhd_test.c index 61f0ea6..2a935b2 100644 --- a/examples/mares_iconhd_test.c +++ b/examples/mares_iconhd_test.c @@ -20,6 +20,7 @@ */ #include // fopen, fwrite, fclose +#include #include @@ -27,7 +28,7 @@ #include "common.h" dc_status_t -test_dump_memory (const char* name, const char* filename) +test_dump_memory (const char* name, const char* filename, unsigned int model) { dc_context_t *context = NULL; dc_device_t *device = NULL; @@ -37,7 +38,7 @@ test_dump_memory (const char* name, const char* filename) dc_context_set_logfunc (context, logfunc, NULL); message ("mares_iconhd_device_open\n"); - dc_status_t rc = mares_iconhd_device_open (&device, context, name); + dc_status_t rc = mares_iconhd_device_open (&device, context, name, model); if (rc != DC_STATUS_SUCCESS) { WARNING ("Error opening serial port."); dc_context_free (context); @@ -88,14 +89,20 @@ int main(int argc, char *argv[]) #else const char* name = "/dev/ttyS0"; #endif + unsigned int model = 0; if (argc > 1) { name = argv[1]; } - message ("DEVICE=%s\n", name); + if (argc > 2) { + model = strtoul (argv[2], NULL, 0); + } - dc_status_t a = test_dump_memory (name, "ICONHD.DMP"); + message ("DEVICE=%s\n", name); + message ("MODEL=0x%02x\n", model); + + dc_status_t a = test_dump_memory (name, "ICONHD.DMP", model); message ("\nSUMMARY\n"); message ("-------\n"); diff --git a/include/libdivecomputer/mares_iconhd.h b/include/libdivecomputer/mares_iconhd.h index 00c1224..38f82b3 100644 --- a/include/libdivecomputer/mares_iconhd.h +++ b/include/libdivecomputer/mares_iconhd.h @@ -31,7 +31,7 @@ extern "C" { #endif /* __cplusplus */ dc_status_t -mares_iconhd_device_open (dc_device_t **device, dc_context_t *context, const char *name); +mares_iconhd_device_open (dc_device_t **device, dc_context_t *context, const char *name, unsigned int model); dc_status_t mares_iconhd_extract_dives (dc_device_t *device, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata); diff --git a/src/descriptor.c b/src/descriptor.c index be089af..ee29372 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -149,6 +149,7 @@ static const dc_descriptor_t g_descriptors[] = { /* Mares Icon HD */ {"Mares", "Icon HD", DC_FAMILY_MARES_ICONHD , 0x14}, {"Mares", "Icon HD Net Ready", DC_FAMILY_MARES_ICONHD , 0x15}, + {"Mares", "Nemo Wide 2", DC_FAMILY_MARES_ICONHD , 0x19}, /* Heinrichs Weikamp */ {"Heinrichs Weikamp", "OSTC", DC_FAMILY_HW_OSTC, 0}, {"Heinrichs Weikamp", "OSTC Mk2", DC_FAMILY_HW_OSTC, 1}, diff --git a/src/device.c b/src/device.c index 3fde549..bb3d765 100644 --- a/src/device.c +++ b/src/device.c @@ -118,7 +118,7 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr rc = mares_darwin_device_open (&device, context, name, dc_descriptor_get_model (descriptor)); break; case DC_FAMILY_MARES_ICONHD: - rc = mares_iconhd_device_open (&device, context, name); + rc = mares_iconhd_device_open (&device, context, name, dc_descriptor_get_model (descriptor)); break; case DC_FAMILY_HW_OSTC: rc = hw_ostc_device_open (&device, context, name); diff --git a/src/mares_iconhd.c b/src/mares_iconhd.c index 9e8dd07..b03f7c6 100644 --- a/src/mares_iconhd.c +++ b/src/mares_iconhd.c @@ -42,11 +42,13 @@ #define ICONHD 0x14 #define ICONHDNET 0x15 +#define NEMOWIDE2 0x19 #define ACK 0xAA #define EOF 0xEA #define SZ_MEMORY 0x100000 +#define SZ_PACKET 0x000100 #define RB_PROFILE_BEGIN 0xA000 #define RB_PROFILE_END SZ_MEMORY @@ -56,6 +58,7 @@ typedef struct mares_iconhd_device_t { serial_t *port; unsigned char fingerprint[10]; unsigned char version[140]; + unsigned int packetsize; } mares_iconhd_device_t; static dc_status_t mares_iconhd_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size); @@ -104,17 +107,10 @@ static dc_status_t mares_iconhd_transfer (mares_iconhd_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, - unsigned int events) + dc_event_progress_t *progress) { dc_device_t *abstract = (dc_device_t *) device; - // Enable progress notifications. - dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; - if (events) { - progress.maximum = asize; - device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); - } - // Send the command to the dive computer. int n = serial_write (device->port, command, csize); if (n != csize) { @@ -158,9 +154,9 @@ mares_iconhd_transfer (mares_iconhd_device_t *device, } // Update and emit a progress event. - if (events) { - progress.current += len; - device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); + if (progress) { + progress->current += len; + device_event_emit (abstract, DC_EVENT_PROGRESS, progress); } nbytes += len; @@ -188,28 +184,46 @@ static dc_status_t mares_iconhd_version (mares_iconhd_device_t *device, unsigned char data[], unsigned int size) { unsigned char command[] = {0xC2, 0x67}; - return mares_iconhd_transfer (device, command, sizeof (command), data, size, 0); + return mares_iconhd_transfer (device, command, sizeof (command), data, size, NULL); } static dc_status_t -mares_iconhd_read (mares_iconhd_device_t *device, unsigned int address, unsigned char data[], unsigned int size, int events) +mares_iconhd_read (mares_iconhd_device_t *device, unsigned int address, unsigned char data[], unsigned int size, dc_event_progress_t *progress) { - unsigned char command[] = {0xE7, 0x42, - (address ) & 0xFF, - (address >> 8) & 0xFF, - (address >> 16) & 0xFF, - (address >> 24) & 0xFF, - (size ) & 0xFF, - (size >> 8) & 0xFF, - (size >> 16) & 0xFF, - (size >> 24) & 0xFF}; - return mares_iconhd_transfer (device, command, sizeof (command), data, size, events); + dc_status_t rc = DC_STATUS_SUCCESS; + + unsigned int nbytes = 0; + while (nbytes < size) { + // Calculate the packet size. + unsigned int len = size - nbytes; + if (device->packetsize && len > device->packetsize) + len = device->packetsize; + + // Read the packet. + unsigned char command[] = {0xE7, 0x42, + (address ) & 0xFF, + (address >> 8) & 0xFF, + (address >> 16) & 0xFF, + (address >> 24) & 0xFF, + (len ) & 0xFF, + (len >> 8) & 0xFF, + (len >> 16) & 0xFF, + (len >> 24) & 0xFF}; + rc = mares_iconhd_transfer (device, command, sizeof (command), data, len, progress); + if (rc != DC_STATUS_SUCCESS) + return rc; + + nbytes += len; + address += len; + data += len; + } + + return rc; } - dc_status_t -mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char *name) +mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model) { if (out == NULL) return DC_STATUS_INVALIDARGS; @@ -228,6 +242,11 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char * device->port = NULL; memset (device->fingerprint, 0, sizeof (device->fingerprint)); memset (device->version, 0, sizeof (device->version)); + if (model == NEMOWIDE2) { + device->packetsize = SZ_PACKET; + } else { + device->packetsize = 0; + } // Open the device. int rc = serial_open (&device->port, context, name); @@ -238,7 +257,11 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char * } // Set the serial communication protocol (256000 8N1). - rc = serial_configure (device->port, BAUDRATE, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + if (model == NEMOWIDE2) { + rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_EVEN, 1, SERIAL_FLOWCONTROL_NONE); + } else { + rc = serial_configure (device->port, BAUDRATE, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + } if (rc == -1) { ERROR (context, "Failed to set the terminal attributes."); serial_close (device->port); @@ -324,7 +347,7 @@ mares_iconhd_device_read (dc_device_t *abstract, unsigned int address, unsigned { mares_iconhd_device_t *device = (mares_iconhd_device_t *) abstract; - return mares_iconhd_read (device, address, data, size, 0); + return mares_iconhd_read (device, address, data, size, NULL); } @@ -340,8 +363,13 @@ mares_iconhd_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) return DC_STATUS_NOMEMORY; } + // Enable progress notifications. + dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; + progress.maximum = SZ_MEMORY; + device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); + return mares_iconhd_read (device, 0, dc_buffer_get_data (buffer), - dc_buffer_get_size (buffer), 1); + dc_buffer_get_size (buffer), &progress); }