From 5fa943d6857662a5da8a60a23b508ce823b88dd9 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Tue, 17 Nov 2009 11:02:26 +0000 Subject: [PATCH] Added the initial implementation for the Cressi Edy. --- examples/Makefile.am | 5 +- examples/cressi_edy_test.c | 122 +++++++++++++++ examples/universal.c | 7 +- msvc/libdivecomputer.vcproj | 12 ++ src/Makefile.am | 6 +- src/cressi.h | 27 ++++ src/cressi_edy.c | 299 ++++++++++++++++++++++++++++++++++++ src/cressi_edy.h | 40 +++++ src/device.h | 3 +- src/libdivecomputer.symbols | 1 + 10 files changed, 518 insertions(+), 4 deletions(-) create mode 100644 examples/cressi_edy_test.c create mode 100644 src/cressi.h create mode 100644 src/cressi_edy.c create mode 100644 src/cressi_edy.h diff --git a/examples/Makefile.am b/examples/Makefile.am index d32c537..85ce161 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -18,7 +18,8 @@ bin_PROGRAMS = \ vtpro \ nemo \ puck \ - ostc + ostc \ + edy if IRDA bin_PROGRAMS += smart @@ -58,6 +59,8 @@ puck_SOURCES = mares_puck_test.c ostc_SOURCES = hw_ostc_test.c +edy_SOURCES = cressi_edy_test.c + if IRDA smart_SOURCES = uwatec_smart_test.c endif diff --git a/examples/cressi_edy_test.c b/examples/cressi_edy_test.c new file mode 100644 index 0000000..8c3c108 --- /dev/null +++ b/examples/cressi_edy_test.c @@ -0,0 +1,122 @@ +/* + * libdivecomputer + * + * Copyright (C) 2009 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 "cressi_edy.h" +#include "utils.h" + + +device_status_t +test_dump_memory (const char* name, const char* filename) +{ + device_t *device = NULL; + + message ("cressi_edy_device_open\n"); + device_status_t rc = cressi_edy_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 ("EDY.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, "EDY.DMP"); + + message ("\nSUMMARY\n"); + message ("-------\n"); + message ("test_dump_memory: %s\n", errmsg (a)); + + message_set_logfile (NULL); + + return 0; +} diff --git a/examples/universal.c b/examples/universal.c index cad26ef..c477d7c 100644 --- a/examples/universal.c +++ b/examples/universal.c @@ -33,6 +33,7 @@ #include #include #include +#include #include typedef struct backend_table_t { @@ -57,7 +58,8 @@ static const backend_table_t g_backends[] = { {"atom2", DEVICE_TYPE_OCEANIC_ATOM2}, {"nemo", DEVICE_TYPE_MARES_NEMO}, {"puck", DEVICE_TYPE_MARES_PUCK}, - {"ostc", DEVICE_TYPE_HW_OSTC} + {"ostc", DEVICE_TYPE_HW_OSTC}, + {"edy", DEVICE_TYPE_CRESSI_EDY} }; static device_type_t @@ -239,6 +241,9 @@ dowork (device_type_t backend, const char *devname, const char *filename, int me case DEVICE_TYPE_HW_OSTC: rc = hw_ostc_device_open (&device, devname); break; + case DEVICE_TYPE_CRESSI_EDY: + rc = cressi_edy_device_open (&device, devname); + break; default: rc = DEVICE_STATUS_ERROR; break; diff --git a/msvc/libdivecomputer.vcproj b/msvc/libdivecomputer.vcproj index 75fb864..bc24629 100644 --- a/msvc/libdivecomputer.vcproj +++ b/msvc/libdivecomputer.vcproj @@ -188,6 +188,10 @@ RelativePath="..\src\checksum.c" > + + @@ -358,6 +362,14 @@ RelativePath="..\src\checksum.h" > + + + + diff --git a/src/Makefile.am b/src/Makefile.am index 9c56206..d361056 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -31,7 +31,9 @@ libdivecomputer_HEADERS = \ mares_nemo.h \ mares_puck.h \ hw.h \ - hw_ostc.h + hw_ostc.h \ + cressi.h \ + cressi_edy.h # # Source files. @@ -72,6 +74,8 @@ libdivecomputer_la_SOURCES = \ mares_puck.h mares_puck.c \ hw.h \ hw_ostc.h hw_ostc.c \ + cressi.h \ + cressi_edy.h cressi_edy.c \ ringbuffer.h ringbuffer.c \ checksum.h checksum.c \ array.h array.c \ diff --git a/src/cressi.h b/src/cressi.h new file mode 100644 index 0000000..015f56c --- /dev/null +++ b/src/cressi.h @@ -0,0 +1,27 @@ +/* + * libdivecomputer + * + * Copyright (C) 2009 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 CRESSI_H +#define CRESSI_H + +#include "cressi_edy.h" + +#endif /* CRESSI_H */ diff --git a/src/cressi_edy.c b/src/cressi_edy.c new file mode 100644 index 0000000..4ac6b90 --- /dev/null +++ b/src/cressi_edy.c @@ -0,0 +1,299 @@ +/* + * libdivecomputer + * + * Copyright (C) 2009 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 "cressi_edy.h" +#include "serial.h" +#include "utils.h" +#include "checksum.h" +#include "array.h" + +#define EXITCODE(rc) \ +( \ + rc == -1 ? DEVICE_STATUS_IO : DEVICE_STATUS_TIMEOUT \ +) + +typedef struct cressi_edy_device_t { + device_t base; + struct serial *port; +} cressi_edy_device_t; + +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_close (device_t *abstract); + +static const device_backend_t cressi_edy_device_backend = { + DEVICE_TYPE_CRESSI_EDY, + NULL, /* set_fingerprint */ + NULL, /* version */ + cressi_edy_device_read, /* read */ + NULL, /* write */ + cressi_edy_device_dump, /* dump */ + NULL, /* foreach */ + cressi_edy_device_close /* close */ +}; + +static int +device_is_cressi_edy (device_t *abstract) +{ + if (abstract == NULL) + return 0; + + return abstract->backend == &cressi_edy_device_backend; +} + + +static device_status_t +cressi_edy_transfer (cressi_edy_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, int trailer) +{ + assert (asize >= csize); + + // Flush the serial input buffer. + int rc = serial_flush (device->port, SERIAL_QUEUE_INPUT); + if (rc == -1) { + WARNING ("Failed to flush the serial input buffer."); + return DEVICE_STATUS_IO; + } + + // 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 trailer of the packet. + if (trailer && answer[asize - 1] != 0x45) { + WARNING ("Unexpected answer trailer byte."); + return DEVICE_STATUS_PROTOCOL; + } + + return DEVICE_STATUS_SUCCESS; +} + + +static device_status_t +cressi_edy_init1 (cressi_edy_device_t *device) +{ + unsigned char command[3] = {0x41, 0x42, 0x43}; + unsigned char answer[6] = {0}; + + return cressi_edy_transfer (device, command, sizeof (command), answer, sizeof (answer), 0); +} + + +static device_status_t +cressi_edy_init2 (cressi_edy_device_t *device) +{ + unsigned char command[1] = {0x44}; + unsigned char answer[2] = {0}; + + return cressi_edy_transfer (device, command, sizeof (command), answer, sizeof (answer), 0); +} + + +static device_status_t +cressi_edy_init3 (cressi_edy_device_t *device) +{ + unsigned char command[1] = {0x0C}; + unsigned char answer[2] = {0}; + + return cressi_edy_transfer (device, command, sizeof (command), answer, sizeof (answer), 1); +} + + +static device_status_t +cressi_edy_quit (cressi_edy_device_t *device) +{ + unsigned char command[1] = {0x46}; + unsigned char answer[1] = {0}; + + return cressi_edy_transfer (device, command, sizeof (command), answer, sizeof (answer), 0); +} + + +device_status_t +cressi_edy_device_open (device_t **out, const char* name) +{ + if (out == NULL) + return DEVICE_STATUS_ERROR; + + // Allocate memory. + cressi_edy_device_t *device = (cressi_edy_device_t *) malloc (sizeof (cressi_edy_device_t)); + if (device == NULL) { + WARNING ("Failed to allocate memory."); + return DEVICE_STATUS_MEMORY; + } + + // Initialize the base class. + device_init (&device->base, &cressi_edy_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 (1200 8N1). + rc = serial_configure (device->port, 1200, 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; + } + + // Set the DTR and clear the RTS line. + if (serial_set_dtr (device->port, 1) == -1 || + serial_set_rts (device->port, 0) == -1) { + WARNING ("Failed to set the DTR/RTS line."); + serial_close (device->port); + free (device); + return DEVICE_STATUS_IO; + } + + // Send the init commands. + cressi_edy_init1 (device); + cressi_edy_init2 (device); + cressi_edy_init3 (device); + + // 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; + } + + *out = (device_t*) device; + + return DEVICE_STATUS_SUCCESS; +} + + +static device_status_t +cressi_edy_device_close (device_t *abstract) +{ + cressi_edy_device_t *device = (cressi_edy_device_t*) abstract; + + if (! device_is_cressi_edy (abstract)) + return DEVICE_STATUS_TYPE_MISMATCH; + + // Send the quit command. + cressi_edy_quit (device); + + // 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 +cressi_edy_device_read (device_t *abstract, unsigned int address, unsigned char data[], unsigned int size) +{ + cressi_edy_device_t *device = (cressi_edy_device_t*) abstract; + + if (! device_is_cressi_edy (abstract)) + return DEVICE_STATUS_TYPE_MISMATCH; + + assert (address % (CRESSI_EDY_PACKET_SIZE / 4)== 0); + assert (size % CRESSI_EDY_PACKET_SIZE == 0); + + // The data transmission is split in packages + // of maximum $CRESSI_EDY_PACKET_SIZE bytes. + + unsigned int nbytes = 0; + while (nbytes < size) { + // Read the package. + unsigned int number = address / (CRESSI_EDY_PACKET_SIZE / 4); + unsigned char answer[3 + CRESSI_EDY_PACKET_SIZE + 1] = {0}; + unsigned char command[3] = {0x52, + (number >> 8) & 0xFF, // high + (number ) & 0xFF}; // low + device_status_t rc = cressi_edy_transfer (device, command, sizeof (command), answer, sizeof (answer), 1); + if (rc != DEVICE_STATUS_SUCCESS) + return rc; + + memcpy (data, answer + 3, CRESSI_EDY_PACKET_SIZE); + + nbytes += CRESSI_EDY_PACKET_SIZE; + address += CRESSI_EDY_PACKET_SIZE; + data += CRESSI_EDY_PACKET_SIZE; + } + + return DEVICE_STATUS_SUCCESS; +} + + +static device_status_t +cressi_edy_device_dump (device_t *abstract, dc_buffer_t *buffer) +{ + if (! device_is_cressi_edy (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, CRESSI_EDY_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), CRESSI_EDY_PACKET_SIZE); +} diff --git a/src/cressi_edy.h b/src/cressi_edy.h new file mode 100644 index 0000000..9ebc762 --- /dev/null +++ b/src/cressi_edy.h @@ -0,0 +1,40 @@ +/* + * libdivecomputer + * + * Copyright (C) 2009 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 CRESSI_EDY_H +#define CRESSI_EDY_H + +#include "device.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define CRESSI_EDY_MEMORY_SIZE 0x8000 +#define CRESSI_EDY_PACKET_SIZE 128 + +device_status_t +cressi_edy_device_open (device_t **device, const char* name); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* CRESSI_EDY_H */ diff --git a/src/device.h b/src/device.h index 3707e46..d375d4a 100644 --- a/src/device.h +++ b/src/device.h @@ -46,7 +46,8 @@ typedef enum device_type_t { DEVICE_TYPE_OCEANIC_VTPRO, DEVICE_TYPE_MARES_NEMO, DEVICE_TYPE_MARES_PUCK, - DEVICE_TYPE_HW_OSTC + DEVICE_TYPE_HW_OSTC, + DEVICE_TYPE_CRESSI_EDY } device_type_t; typedef enum device_status_t { diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index ab5a569..a6af5ad 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -45,6 +45,7 @@ message message_set_logfile #ifdef SERIAL +cressi_edy_device_open mares_nemo_device_open mares_nemo_extract_dives mares_puck_device_open