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!
This commit is contained in:
Jef Driesen 2012-12-15 20:25:16 +01:00
parent 74b91f2791
commit 3d3c3f6039
5 changed files with 70 additions and 34 deletions

View File

@ -20,6 +20,7 @@
*/
#include <stdio.h> // fopen, fwrite, fclose
#include <stdlib.h>
#include <libdivecomputer/mares_iconhd.h>
@ -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");

View File

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

View File

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

View File

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

View File

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