diff --git a/examples/Makefile.am b/examples/Makefile.am index 278326c..7a376bc 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -20,7 +20,8 @@ bin_PROGRAMS = \ puck \ iconhd \ ostc \ - edy + edy \ + n2ition3 if IRDA bin_PROGRAMS += smart @@ -64,6 +65,8 @@ ostc_SOURCES = hw_ostc_test.c edy_SOURCES = cressi_edy_test.c +n2ition3_SOURCES = zeagle_n2ition3_test.c + if IRDA smart_SOURCES = uwatec_smart_test.c endif diff --git a/examples/universal.c b/examples/universal.c index 227fb6f..c72a80a 100644 --- a/examples/universal.c +++ b/examples/universal.c @@ -41,6 +41,7 @@ #include #include #include +#include #include static const char *g_cachedir = NULL; @@ -88,7 +89,8 @@ static const backend_table_t g_backends[] = { {"puck", DEVICE_TYPE_MARES_PUCK}, {"iconhd", DEVICE_TYPE_MARES_ICONHD}, {"ostc", DEVICE_TYPE_HW_OSTC}, - {"edy", DEVICE_TYPE_CRESSI_EDY} + {"edy", DEVICE_TYPE_CRESSI_EDY}, + {"n2ition3", DEVICE_TYPE_ZEAGLE_N2ITION3} }; static device_type_t @@ -600,6 +602,9 @@ dowork (device_type_t backend, const char *devname, const char *rawfile, const c case DEVICE_TYPE_CRESSI_EDY: rc = cressi_edy_device_open (&device, devname); break; + case DEVICE_TYPE_ZEAGLE_N2ITION3: + rc = zeagle_n2ition3_device_open (&device, devname); + break; default: rc = DEVICE_STATUS_ERROR; break; diff --git a/examples/zeagle_n2ition3_test.c b/examples/zeagle_n2ition3_test.c new file mode 100644 index 0000000..386ba6d --- /dev/null +++ b/examples/zeagle_n2ition3_test.c @@ -0,0 +1,122 @@ +/* + * libdivecomputer + * + * Copyright (C) 2010 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include // fopen, fwrite, fclose + +#include "zeagle_n2ition3.h" +#include "utils.h" + + +device_status_t +test_dump_memory (const char* name, const char* filename) +{ + device_t *device = NULL; + + message ("zeagle_n2ition3_device_open\n"); + device_status_t rc = zeagle_n2ition3_device_open (&device, name); + if (rc != DEVICE_STATUS_SUCCESS) { + WARNING ("Error opening serial port."); + return rc; + } + + dc_buffer_t *buffer = dc_buffer_new (0); + + message ("device_dump\n"); + rc = device_dump (device, buffer); + if (rc != DEVICE_STATUS_SUCCESS) { + WARNING ("Cannot read memory."); + dc_buffer_free (buffer); + device_close (device); + return rc; + } + + message ("Dumping data\n"); + FILE* fp = fopen (filename, "wb"); + if (fp != NULL) { + fwrite (dc_buffer_get_data (buffer), sizeof (unsigned char), dc_buffer_get_size (buffer), fp); + fclose (fp); + } + + dc_buffer_free (buffer); + + message ("device_close\n"); + rc = device_close (device); + if (rc != DEVICE_STATUS_SUCCESS) { + WARNING ("Cannot close device."); + return rc; + } + + return DEVICE_STATUS_SUCCESS; +} + + +const char* +errmsg (device_status_t rc) +{ + switch (rc) { + case DEVICE_STATUS_SUCCESS: + return "Success"; + case DEVICE_STATUS_UNSUPPORTED: + return "Unsupported operation"; + case DEVICE_STATUS_TYPE_MISMATCH: + return "Device type mismatch"; + case DEVICE_STATUS_ERROR: + return "Generic error"; + case DEVICE_STATUS_IO: + return "Input/output error"; + case DEVICE_STATUS_MEMORY: + return "Memory error"; + case DEVICE_STATUS_PROTOCOL: + return "Protocol error"; + case DEVICE_STATUS_TIMEOUT: + return "Timeout"; + default: + return "Unknown error"; + } +} + + +int main(int argc, char *argv[]) +{ + message_set_logfile ("N2ITION3.LOG"); + +#ifdef _WIN32 + const char* name = "COM1"; +#else + const char* name = "/dev/ttyS0"; +#endif + + if (argc > 1) { + name = argv[1]; + } + + message ("DEVICE=%s\n", name); + + device_status_t a = test_dump_memory (name, "N2ITION3.DMP"); + + message ("\nSUMMARY\n"); + message ("-------\n"); + message ("test_dump_memory: %s\n", errmsg (a)); + + message_set_logfile (NULL); + + return 0; +} diff --git a/src/Makefile.am b/src/Makefile.am index 1a95540..0cd74ec 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -36,7 +36,9 @@ libdivecomputer_HEADERS = \ hw.h \ hw_ostc.h \ cressi.h \ - cressi_edy.h + cressi_edy.h \ + zeagle.h \ + zeagle_n2ition3.h # # Source files. @@ -84,6 +86,8 @@ libdivecomputer_la_SOURCES = \ hw_ostc.h hw_ostc.c hw_ostc_parser.c \ cressi.h \ cressi_edy.h cressi_edy.c cressi_edy_parser.c \ + zeagle.h \ + zeagle_n2ition3.h zeagle_n2ition3.c \ ringbuffer.h ringbuffer.c \ checksum.h checksum.c \ array.h array.c \ diff --git a/src/device.h b/src/device.h index bbf6bbd..b119200 100644 --- a/src/device.h +++ b/src/device.h @@ -49,7 +49,8 @@ typedef enum device_type_t { DEVICE_TYPE_MARES_PUCK, DEVICE_TYPE_MARES_ICONHD, DEVICE_TYPE_HW_OSTC, - DEVICE_TYPE_CRESSI_EDY + DEVICE_TYPE_CRESSI_EDY, + DEVICE_TYPE_ZEAGLE_N2ITION3 } device_type_t; typedef enum device_status_t { diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index 613350d..3b4612f 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -111,3 +111,4 @@ uwatec_smart_device_set_timestamp uwatec_smart_extract_dives hw_ostc_device_open hw_ostc_extract_dives +zeagle_n2ition3_device_open diff --git a/src/zeagle.h b/src/zeagle.h new file mode 100644 index 0000000..5d42cfb --- /dev/null +++ b/src/zeagle.h @@ -0,0 +1,27 @@ +/* + * libdivecomputer + * + * Copyright (C) 2010 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef ZEAGLE_H +#define ZEAGLE_H + +#include "zeagle_n2ition3.h" + +#endif /* CRESSI_H */ diff --git a/src/zeagle_n2ition3.c b/src/zeagle_n2ition3.c new file mode 100644 index 0000000..fee4cf0 --- /dev/null +++ b/src/zeagle_n2ition3.c @@ -0,0 +1,260 @@ +/* + * libdivecomputer + * + * Copyright (C) 2010 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include // memcpy, memcmp +#include // malloc, free +#include // assert + +#include "device-private.h" +#include "zeagle_n2ition3.h" +#include "serial.h" +#include "utils.h" +#include "checksum.h" +#include "array.h" +#include "ringbuffer.h" + +#define EXITCODE(rc) \ +( \ + rc == -1 ? DEVICE_STATUS_IO : DEVICE_STATUS_TIMEOUT \ +) + +typedef struct zeagle_n2ition3_device_t { + device_t base; + struct serial *port; +} zeagle_n2ition3_device_t; + +static device_status_t zeagle_n2ition3_device_read (device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); +static device_status_t zeagle_n2ition3_device_dump (device_t *abstract, dc_buffer_t *buffer); +static device_status_t zeagle_n2ition3_device_close (device_t *abstract); + +static const device_backend_t zeagle_n2ition3_device_backend = { + DEVICE_TYPE_ZEAGLE_N2ITION3, + NULL, /* set_fingerprint */ + NULL, /* version */ + zeagle_n2ition3_device_read, /* read */ + NULL, /* write */ + zeagle_n2ition3_device_dump, /* dump */ + NULL, /* foreach */ + zeagle_n2ition3_device_close /* close */ +}; + +static int +device_is_zeagle_n2ition3 (device_t *abstract) +{ + if (abstract == NULL) + return 0; + + return abstract->backend == &zeagle_n2ition3_device_backend; +} + + +static device_status_t +zeagle_n2ition3_packet (zeagle_n2ition3_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) +{ + assert (asize >= csize + 5); + + // Send the command to the device. + int n = serial_write (device->port, command, csize); + if (n != csize) { + WARNING ("Failed to send the command."); + return EXITCODE (n); + } + + // Receive the answer of the device. + n = serial_read (device->port, answer, asize); + if (n != asize) { + WARNING ("Failed to receive the answer."); + return EXITCODE (n); + } + + // Verify the echo. + if (memcmp (answer, command, csize) != 0) { + WARNING ("Unexpected echo."); + return DEVICE_STATUS_PROTOCOL; + } + + // Verify the header and trailer of the packet. + if (answer[csize] != 0x02 && answer[asize - 1] != 0x03) { + WARNING ("Unexpected answer header/trailer byte."); + return DEVICE_STATUS_PROTOCOL; + } + + // Verify the size of the packet. + if (array_uint16_le (answer + csize + 1) + csize + 5 != asize) { + WARNING ("Unexpected answer size."); + return DEVICE_STATUS_PROTOCOL; + } + + // Verify the checksum of the packet. + unsigned char crc = answer[asize - 2]; + unsigned char ccrc = ~checksum_add_uint8 (answer + csize + 3, asize - csize - 5, 0x00) + 1; + if (crc != ccrc) { + WARNING ("Unexpected answer checksum."); + return DEVICE_STATUS_PROTOCOL; + } + + return DEVICE_STATUS_SUCCESS; +} + +static device_status_t +zeagle_n2ition3_init (zeagle_n2ition3_device_t *device) +{ + unsigned char answer[6 + 13] = {0}; + unsigned char command[6] = {0x02, 0x01, 0x00, 0x41, 0xBF, 0x03}; + command[11] = ~checksum_add_uint8 (command + 3, 8, 0x00) + 1; + + return zeagle_n2ition3_packet (device, command, sizeof (command), answer, sizeof (answer)); +} + +device_status_t +zeagle_n2ition3_device_open (device_t **out, const char* name) +{ + if (out == NULL) + return DEVICE_STATUS_ERROR; + + // Allocate memory. + zeagle_n2ition3_device_t *device = (zeagle_n2ition3_device_t *) malloc (sizeof (zeagle_n2ition3_device_t)); + if (device == NULL) { + WARNING ("Failed to allocate memory."); + return DEVICE_STATUS_MEMORY; + } + + // Initialize the base class. + device_init (&device->base, &zeagle_n2ition3_device_backend); + + // Set the default values. + device->port = NULL; + + // Open the device. + int rc = serial_open (&device->port, name); + if (rc == -1) { + WARNING ("Failed to open the serial port."); + free (device); + return DEVICE_STATUS_IO; + } + + // Set the serial communication protocol (4800 8N1). + rc = serial_configure (device->port, 4800, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); + if (rc == -1) { + WARNING ("Failed to set the terminal attributes."); + serial_close (device->port); + free (device); + return DEVICE_STATUS_IO; + } + + // Set the timeout for receiving data (1000 ms). + if (serial_set_timeout (device->port, 1000) == -1) { + WARNING ("Failed to set the timeout."); + serial_close (device->port); + free (device); + return DEVICE_STATUS_IO; + } + + // Make sure everything is in a sane state. + serial_flush (device->port, SERIAL_QUEUE_BOTH); + + // Send the init commands. + zeagle_n2ition3_init (device); + + *out = (device_t *) device; + + return DEVICE_STATUS_SUCCESS; +} + + +static device_status_t +zeagle_n2ition3_device_close (device_t *abstract) +{ + zeagle_n2ition3_device_t *device = (zeagle_n2ition3_device_t*) abstract; + + if (! device_is_zeagle_n2ition3 (abstract)) + return DEVICE_STATUS_TYPE_MISMATCH; + + // Close the device. + if (serial_close (device->port) == -1) { + free (device); + return DEVICE_STATUS_IO; + } + + // Free memory. + free (device); + + return DEVICE_STATUS_SUCCESS; +} + + +static device_status_t +zeagle_n2ition3_device_read (device_t *abstract, unsigned int address, unsigned char data[], unsigned int size) +{ + zeagle_n2ition3_device_t *device = (zeagle_n2ition3_device_t*) abstract; + + if (! device_is_zeagle_n2ition3 (abstract)) + return DEVICE_STATUS_TYPE_MISMATCH; + + // The data transmission is split in packages + // of maximum $ZEAGLE_N2ITION3_PACKET_SIZE bytes. + + unsigned int nbytes = 0; + while (nbytes < size) { + // Calculate the package size. + unsigned int len = size - nbytes; + if (len > ZEAGLE_N2ITION3_PACKET_SIZE) + len = ZEAGLE_N2ITION3_PACKET_SIZE; + + // Read the package. + unsigned char answer[13 + ZEAGLE_N2ITION3_PACKET_SIZE + 6] = {0}; + unsigned char command[13] = {0x02, 0x08, 0x00, 0x4D, + (address ) & 0xFF, // low + (address >> 8) & 0xFF, // high + len, // count + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}; + command[11] = ~checksum_add_uint8 (command + 3, 8, 0x00) + 1; + device_status_t rc = zeagle_n2ition3_packet (device, command, sizeof (command), answer, 13 + len + 6); + if (rc != DEVICE_STATUS_SUCCESS) + return rc; + + memcpy (data, answer + 17, len); + + nbytes += len; + address += len; + data += len; + } + + return DEVICE_STATUS_SUCCESS; +} + + +static device_status_t +zeagle_n2ition3_device_dump (device_t *abstract, dc_buffer_t *buffer) +{ + if (! device_is_zeagle_n2ition3 (abstract)) + return DEVICE_STATUS_TYPE_MISMATCH; + + // Erase the current contents of the buffer and + // allocate the required amount of memory. + if (!dc_buffer_clear (buffer) || !dc_buffer_resize (buffer, ZEAGLE_N2ITION3_MEMORY_SIZE)) { + WARNING ("Insufficient buffer space available."); + return DEVICE_STATUS_MEMORY; + } + + return device_dump_read (abstract, dc_buffer_get_data (buffer), + dc_buffer_get_size (buffer), ZEAGLE_N2ITION3_PACKET_SIZE); +} diff --git a/src/zeagle_n2ition3.h b/src/zeagle_n2ition3.h new file mode 100644 index 0000000..54e6002 --- /dev/null +++ b/src/zeagle_n2ition3.h @@ -0,0 +1,40 @@ +/* + * libdivecomputer + * + * Copyright (C) 2010 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef ZEAGLE_N2ITION3_H +#define ZEAGLE_N2ITION3_H + +#include "device.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define ZEAGLE_N2ITION3_MEMORY_SIZE 0x8000 +#define ZEAGLE_N2ITION3_PACKET_SIZE 64 + +device_status_t +zeagle_n2ition3_device_open (device_t **device, const char* name); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* ZEAGLE_N2ITION3_H */