diff --git a/examples/common.c b/examples/common.c index 0b4f95b..3c4561b 100644 --- a/examples/common.c +++ b/examples/common.c @@ -41,42 +41,43 @@ typedef struct backend_table_t { const char *name; dc_family_t type; + unsigned int model; } backend_table_t; static const backend_table_t g_backends[] = { - {"solution", DC_FAMILY_SUUNTO_SOLUTION}, - {"eon", DC_FAMILY_SUUNTO_EON}, - {"vyper", DC_FAMILY_SUUNTO_VYPER}, - {"vyper2", DC_FAMILY_SUUNTO_VYPER2}, - {"d9", DC_FAMILY_SUUNTO_D9}, - {"eonsteel", DC_FAMILY_SUUNTO_EONSTEEL}, - {"aladin", DC_FAMILY_UWATEC_ALADIN}, - {"memomouse", DC_FAMILY_UWATEC_MEMOMOUSE}, - {"smart", DC_FAMILY_UWATEC_SMART}, - {"meridian", DC_FAMILY_UWATEC_MERIDIAN}, - {"sensus", DC_FAMILY_REEFNET_SENSUS}, - {"sensuspro", DC_FAMILY_REEFNET_SENSUSPRO}, - {"sensusultra", DC_FAMILY_REEFNET_SENSUSULTRA}, - {"vtpro", DC_FAMILY_OCEANIC_VTPRO}, - {"veo250", DC_FAMILY_OCEANIC_VEO250}, - {"atom2", DC_FAMILY_OCEANIC_ATOM2}, - {"nemo", DC_FAMILY_MARES_NEMO}, - {"puck", DC_FAMILY_MARES_PUCK}, - {"darwin", DC_FAMILY_MARES_DARWIN}, - {"iconhd", DC_FAMILY_MARES_ICONHD}, - {"ostc", DC_FAMILY_HW_OSTC}, - {"frog", DC_FAMILY_HW_FROG}, - {"ostc3", DC_FAMILY_HW_OSTC3}, - {"edy", DC_FAMILY_CRESSI_EDY}, - {"leonardo", DC_FAMILY_CRESSI_LEONARDO}, - {"n2ition3", DC_FAMILY_ZEAGLE_N2ITION3}, - {"cobalt", DC_FAMILY_ATOMICS_COBALT}, - {"predator", DC_FAMILY_SHEARWATER_PREDATOR}, - {"petrel", DC_FAMILY_SHEARWATER_PETREL}, - {"nitekq", DC_FAMILY_DIVERITE_NITEKQ}, - {"aqualand", DC_FAMILY_CITIZEN_AQUALAND}, - {"idive", DC_FAMILY_DIVESYSTEM_IDIVE}, - {"cochran", DC_FAMILY_COCHRAN_COMMANDER}, + {"solution", DC_FAMILY_SUUNTO_SOLUTION, 0}, + {"eon", DC_FAMILY_SUUNTO_EON, 0}, + {"vyper", DC_FAMILY_SUUNTO_VYPER, 0x0A}, + {"vyper2", DC_FAMILY_SUUNTO_VYPER2, 0x10}, + {"d9", DC_FAMILY_SUUNTO_D9, 0x0E}, + {"eonsteel", DC_FAMILY_SUUNTO_EONSTEEL, 0}, + {"aladin", DC_FAMILY_UWATEC_ALADIN, 0x3F}, + {"memomouse", DC_FAMILY_UWATEC_MEMOMOUSE, 0}, + {"smart", DC_FAMILY_UWATEC_SMART, 0x10}, + {"meridian", DC_FAMILY_UWATEC_MERIDIAN, 0x20}, + {"sensus", DC_FAMILY_REEFNET_SENSUS, 1}, + {"sensuspro", DC_FAMILY_REEFNET_SENSUSPRO, 2}, + {"sensusultra", DC_FAMILY_REEFNET_SENSUSULTRA, 3}, + {"vtpro", DC_FAMILY_OCEANIC_VTPRO, 0x4245}, + {"veo250", DC_FAMILY_OCEANIC_VEO250, 0x424C}, + {"atom2", DC_FAMILY_OCEANIC_ATOM2, 0x4342}, + {"nemo", DC_FAMILY_MARES_NEMO, 0}, + {"puck", DC_FAMILY_MARES_PUCK, 7}, + {"darwin", DC_FAMILY_MARES_DARWIN, 0}, + {"iconhd", DC_FAMILY_MARES_ICONHD, 0x14}, + {"ostc", DC_FAMILY_HW_OSTC, 0}, + {"frog", DC_FAMILY_HW_FROG, 0}, + {"ostc3", DC_FAMILY_HW_OSTC3, 0x0A}, + {"edy", DC_FAMILY_CRESSI_EDY, 0x08}, + {"leonardo", DC_FAMILY_CRESSI_LEONARDO, 1}, + {"n2ition3", DC_FAMILY_ZEAGLE_N2ITION3, 0}, + {"cobalt", DC_FAMILY_ATOMICS_COBALT, 0}, + {"predator", DC_FAMILY_SHEARWATER_PREDATOR, 2}, + {"petrel", DC_FAMILY_SHEARWATER_PETREL, 3}, + {"nitekq", DC_FAMILY_DIVERITE_NITEKQ, 0}, + {"aqualand", DC_FAMILY_CITIZEN_AQUALAND, 0}, + {"idive", DC_FAMILY_DIVESYSTEM_IDIVE, 0x03}, + {"cochran", DC_FAMILY_COCHRAN_COMMANDER, 0}, }; const char * @@ -132,6 +133,17 @@ dctool_family_name (dc_family_t type) return NULL; } +unsigned int +dctool_family_model (dc_family_t type) +{ + for (unsigned int i = 0; i < C_ARRAY_SIZE (g_backends); ++i) { + if (g_backends[i].type == type) + return g_backends[i].model; + } + + return 0; +} + void dctool_event_cb (dc_device_t *device, dc_event_type_t event, const void *data, void *userdata) { diff --git a/examples/common.h b/examples/common.h index f17d578..edb7872 100644 --- a/examples/common.h +++ b/examples/common.h @@ -39,6 +39,9 @@ dctool_family_type (const char *name); const char * dctool_family_name (dc_family_t type); +unsigned int +dctool_family_model (dc_family_t type); + void dctool_event_cb (dc_device_t *device, dc_event_type_t event, const void *data, void *userdata); diff --git a/examples/dctool.c b/examples/dctool.c index b1c9e0f..df7fe01 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -175,6 +175,7 @@ main (int argc, char *argv[]) const char *device = NULL; dc_family_t family = DC_FAMILY_NULL; unsigned int model = 0; + unsigned int have_family = 0, have_model = 0; // Parse the command-line options. int opt = 0; @@ -203,9 +204,11 @@ main (int argc, char *argv[]) break; case 'f': family = dctool_family_type (optarg); + have_family = 1; break; case 'm': model = strtoul (optarg, NULL, 0); + have_model = 1; break; case 'l': logfile = optarg; @@ -229,6 +232,11 @@ main (int argc, char *argv[]) optreset = 1; #endif + // Set the default model number. + if (have_family && !have_model) { + model = dctool_family_model (family); + } + // Translate the help option into a command. char *argv_help[] = {(char *) "help", NULL, NULL}; if (help || argv[0] == NULL) { diff --git a/examples/dctool_parse.c b/examples/dctool_parse.c index 5ce1998..9f55ca0 100644 --- a/examples/dctool_parse.c +++ b/examples/dctool_parse.c @@ -61,108 +61,12 @@ parse (dc_buffer_t *buffer, dc_context_t *context, dc_descriptor_t *descriptor, { dc_status_t rc = DC_STATUS_SUCCESS; dc_parser_t *parser = NULL; - dc_family_t family = dc_descriptor_get_type (descriptor); - unsigned int model = dc_descriptor_get_model (descriptor); unsigned char *data = dc_buffer_get_data (buffer); unsigned int size = dc_buffer_get_size (buffer); // Create the parser. message ("Creating the parser.\n"); - switch (family) { - case DC_FAMILY_SUUNTO_SOLUTION: - rc = suunto_solution_parser_create (&parser, context); - break; - case DC_FAMILY_SUUNTO_EON: - rc = suunto_eon_parser_create (&parser, context, 0); - break; - case DC_FAMILY_SUUNTO_VYPER: - if (model == 0x01) - rc = suunto_eon_parser_create (&parser, context, 1); - else - rc = suunto_vyper_parser_create (&parser, context); - break; - case DC_FAMILY_SUUNTO_VYPER2: - case DC_FAMILY_SUUNTO_D9: - rc = suunto_d9_parser_create (&parser, context, model, 0); - break; - case DC_FAMILY_SUUNTO_EONSTEEL: - rc = suunto_eonsteel_parser_create(&parser, context, model); - break; - case DC_FAMILY_UWATEC_ALADIN: - case DC_FAMILY_UWATEC_MEMOMOUSE: - rc = uwatec_memomouse_parser_create (&parser, context, devtime, systime); - break; - case DC_FAMILY_UWATEC_SMART: - case DC_FAMILY_UWATEC_MERIDIAN: - rc = uwatec_smart_parser_create (&parser, context, model, devtime, systime); - break; - case DC_FAMILY_REEFNET_SENSUS: - rc = reefnet_sensus_parser_create (&parser, context, devtime, systime); - break; - case DC_FAMILY_REEFNET_SENSUSPRO: - rc = reefnet_sensuspro_parser_create (&parser, context, devtime, systime); - break; - case DC_FAMILY_REEFNET_SENSUSULTRA: - rc = reefnet_sensusultra_parser_create (&parser, context, devtime, systime); - break; - case DC_FAMILY_OCEANIC_VTPRO: - rc = oceanic_vtpro_parser_create (&parser, context); - break; - case DC_FAMILY_OCEANIC_VEO250: - rc = oceanic_veo250_parser_create (&parser, context, model); - break; - case DC_FAMILY_OCEANIC_ATOM2: - if (model == REACTPROWHITE) - rc = oceanic_veo250_parser_create (&parser, context, model); - else - rc = oceanic_atom2_parser_create (&parser, context, model, 0); - break; - case DC_FAMILY_MARES_NEMO: - case DC_FAMILY_MARES_PUCK: - rc = mares_nemo_parser_create (&parser, context, model); - break; - case DC_FAMILY_MARES_DARWIN: - rc = mares_darwin_parser_create (&parser, context, model); - break; - case DC_FAMILY_MARES_ICONHD: - rc = mares_iconhd_parser_create (&parser, context, model); - break; - case DC_FAMILY_HW_OSTC: - rc = hw_ostc_parser_create (&parser, context, 0, 0); - break; - case DC_FAMILY_HW_FROG: - case DC_FAMILY_HW_OSTC3: - rc = hw_ostc_parser_create (&parser, context, 0, 1); - break; - case DC_FAMILY_CRESSI_EDY: - case DC_FAMILY_ZEAGLE_N2ITION3: - rc = cressi_edy_parser_create (&parser, context, model); - break; - case DC_FAMILY_CRESSI_LEONARDO: - rc = cressi_leonardo_parser_create (&parser, context); - break; - case DC_FAMILY_ATOMICS_COBALT: - rc = atomics_cobalt_parser_create (&parser, context); - break; - case DC_FAMILY_SHEARWATER_PREDATOR: - rc = shearwater_predator_parser_create (&parser, context, 0); - break; - case DC_FAMILY_SHEARWATER_PETREL: - rc = shearwater_petrel_parser_create (&parser, context, 0); - break; - case DC_FAMILY_DIVERITE_NITEKQ: - rc = diverite_nitekq_parser_create (&parser, context); - break; - case DC_FAMILY_CITIZEN_AQUALAND: - rc = citizen_aqualand_parser_create (&parser, context); - break; - case DC_FAMILY_DIVESYSTEM_IDIVE: - rc = divesystem_idive_parser_create2 (&parser, context, model); - break; - default: - rc = DC_STATUS_INVALIDARGS; - break; - } + rc = dc_parser_new2 (&parser, context, descriptor, devtime, systime); if (rc != DC_STATUS_SUCCESS) { ERROR ("Error creating the parser."); goto cleanup; diff --git a/include/libdivecomputer/Makefile.am b/include/libdivecomputer/Makefile.am index 3444c1c..778037f 100644 --- a/include/libdivecomputer/Makefile.am +++ b/include/libdivecomputer/Makefile.am @@ -55,5 +55,4 @@ libdivecomputer_HEADERS = \ divesystem.h \ divesystem_idive.h \ cochran.h \ - cochran_commander.h \ - custom_serial.h + cochran_commander.h diff --git a/include/libdivecomputer/custom_serial.h b/include/libdivecomputer/custom_serial.h deleted file mode 100644 index a27d519..0000000 --- a/include/libdivecomputer/custom_serial.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * libdivecomputer - * - * Copyright (C) 2015 Claudiu Olteanu - * base on code that is Copyright (C) 2008 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 CUSTOM_SERIAL_H -#define CUSTOM_SERIAL_H - -#include -#include - -#include "context.h" -#include "descriptor.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -typedef struct serial_t serial_t; - -typedef struct dc_serial_operations_t -{ - int (*open) (serial_t **device, dc_context_t *context, const char *name); - int (*close) (serial_t *device); - int (*read) (serial_t *device, void* data, unsigned int size); - int (*write) (serial_t *device, const void* data, unsigned int size); - int (*flush) (serial_t *device, int queue); - int (*get_received) (serial_t *device); - int (*get_transmitted) (serial_t *device); - int (*set_timeout) (serial_t *device, long timeout); -} dc_serial_operations_t; - -typedef struct dc_serial_t { - serial_t *port; //serial device port - dc_transport_t type; //the type of the transport (USB, SERIAL, IRDA, BLUETOOTH) - void *data; //specific data for serial device - const dc_serial_operations_t *ops; //reference to a custom set of operations -} dc_serial_t; - -void dc_serial_init(dc_serial_t *device, void *data, const dc_serial_operations_t *ops); - -dc_status_t dc_serial_native_open(dc_serial_t **serial, dc_context_t *context, const char *devname); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* CUSTOM_SERIAL_H */ diff --git a/include/libdivecomputer/descriptor.h b/include/libdivecomputer/descriptor.h index f1c815d..b227973 100644 --- a/include/libdivecomputer/descriptor.h +++ b/include/libdivecomputer/descriptor.h @@ -57,6 +57,9 @@ dc_descriptor_get_type (dc_descriptor_t *descriptor); unsigned int dc_descriptor_get_model (dc_descriptor_t *descriptor); +unsigned int +dc_descriptor_get_serial (dc_descriptor_t *descriptor); + dc_transport_t dc_descriptor_get_transport (dc_descriptor_t *descriptor); diff --git a/include/libdivecomputer/device.h b/include/libdivecomputer/device.h index 60590b5..c0868a3 100644 --- a/include/libdivecomputer/device.h +++ b/include/libdivecomputer/device.h @@ -28,7 +28,6 @@ #include "descriptor.h" #include "buffer.h" #include "datetime.h" -#include "custom_serial.h" #ifdef __cplusplus extern "C" { @@ -43,6 +42,7 @@ typedef enum dc_event_type_t { } dc_event_type_t; typedef struct dc_device_t dc_device_t; +typedef struct dc_serial_t dc_serial_t; typedef struct dc_event_progress_t { unsigned int current; diff --git a/include/libdivecomputer/hw_ostc.h b/include/libdivecomputer/hw_ostc.h index 91fe714..7a4cfe3 100644 --- a/include/libdivecomputer/hw_ostc.h +++ b/include/libdivecomputer/hw_ostc.h @@ -65,7 +65,7 @@ dc_status_t hw_ostc_extract_dives (dc_device_t *device, const unsigned char data[], unsigned int size, dc_dive_callback_t callback, void *userdata); dc_status_t -hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial, unsigned int frog); +hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial, unsigned int hwos); dc_status_t hw_ostc_device_fwupdate (dc_device_t *abstract, const char *filename); diff --git a/include/libdivecomputer/hw_ostc3.h b/include/libdivecomputer/hw_ostc3.h index 8463cb2..e463d04 100644 --- a/include/libdivecomputer/hw_ostc3.h +++ b/include/libdivecomputer/hw_ostc3.h @@ -27,7 +27,6 @@ #include "device.h" #include "parser.h" #include "buffer.h" -#include "custom_serial.h" #ifdef __cplusplus extern "C" { @@ -69,6 +68,9 @@ hw_ostc3_device_config_reset (dc_device_t *abstract); dc_status_t hw_ostc3_device_fwupdate (dc_device_t *abstract, const char *filename); +dc_status_t +hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int model); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/include/libdivecomputer/oceanic_vtpro.h b/include/libdivecomputer/oceanic_vtpro.h index ba693f6..f6d2a64 100644 --- a/include/libdivecomputer/oceanic_vtpro.h +++ b/include/libdivecomputer/oceanic_vtpro.h @@ -33,6 +33,9 @@ extern "C" { dc_status_t oceanic_vtpro_device_open (dc_device_t **device, dc_context_t *context, const char *name); +dc_status_t +oceanic_vtpro_device_open2 (dc_device_t **device, dc_context_t *context, const char *name, unsigned int model); + dc_status_t oceanic_vtpro_device_version (dc_device_t *device, unsigned char data[], unsigned int size); @@ -42,6 +45,9 @@ oceanic_vtpro_device_keepalive (dc_device_t *device); dc_status_t oceanic_vtpro_parser_create (dc_parser_t **parser, dc_context_t *context); +dc_status_t +oceanic_vtpro_parser_create2 (dc_parser_t **parser, dc_context_t *context, unsigned int model); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/include/libdivecomputer/parser.h b/include/libdivecomputer/parser.h index 626ebee..a3ffe6e 100644 --- a/include/libdivecomputer/parser.h +++ b/include/libdivecomputer/parser.h @@ -23,6 +23,8 @@ #define DC_PARSER_H #include "common.h" +#include "context.h" +#include "descriptor.h" #include "device.h" #include "datetime.h" @@ -243,6 +245,9 @@ typedef void (*dc_sample_callback_t) (dc_sample_type_t type, dc_sample_value_t v dc_status_t dc_parser_new (dc_parser_t **parser, dc_device_t *device); +dc_status_t +dc_parser_new2 (dc_parser_t **parser, dc_context_t *context, dc_descriptor_t *descriptor, unsigned int devtime, dc_ticks_t systime); + dc_family_t dc_parser_get_type (dc_parser_t *parser); diff --git a/src/Makefile.am b/src/Makefile.am index ab091dc..eba4151 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -66,8 +66,7 @@ libdivecomputer_la_SOURCES = \ array.h array.c \ buffer.c \ cochran_commander.h cochran_commander.c \ - cochran_commander_parser.c \ - custom_serial.c + cochran_commander_parser.c if OS_WIN32 libdivecomputer_la_SOURCES += serial.h serial_win32.c diff --git a/src/citizen_aqualand.c b/src/citizen_aqualand.c index 774a3e4..68cfc8c 100644 --- a/src/citizen_aqualand.c +++ b/src/citizen_aqualand.c @@ -33,14 +33,9 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &citizen_aqualand_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - typedef struct citizen_aqualand_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; unsigned char fingerprint[8]; } citizen_aqualand_device_t; @@ -82,38 +77,36 @@ citizen_aqualand_device_open (dc_device_t **out, dc_context_t *context, const ch memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (4800 8N1). - rc = serial_configure (device->port, 4800, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 4800, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (1000ms). - if (serial_set_timeout (device->port, 1000) == -1) { + status = dc_serial_set_timeout (device->port, 1000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Make sure everything is in a sane state. - serial_sleep (device->port, 300); - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_sleep (device->port, 300); + dc_serial_purge (device->port, DC_DIRECTION_ALL); *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -125,10 +118,12 @@ citizen_aqualand_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; citizen_aqualand_device_t *device = (citizen_aqualand_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -154,6 +149,7 @@ citizen_aqualand_device_set_fingerprint (dc_device_t *abstract, const unsigned c static dc_status_t citizen_aqualand_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) { + dc_status_t status = DC_STATUS_SUCCESS; citizen_aqualand_device_t *device = (citizen_aqualand_device_t *) abstract; // Erase the current contents of the buffer and @@ -163,49 +159,49 @@ citizen_aqualand_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) return DC_STATUS_NOMEMORY; } - serial_set_dtr (device->port, 1); + dc_serial_set_dtr (device->port, 1); // Send the init byte. const unsigned char init[] = {0x7F}; - int n = serial_write (device->port, init, sizeof (init)); - if (n != sizeof (init)) { + status = dc_serial_write (device->port, init, sizeof (init), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } - serial_sleep(device->port, 1200); + dc_serial_sleep(device->port, 1200); // Send the command. const unsigned char command[] = {0xFF}; - n = serial_write (device->port, command, sizeof (command)); - if (n != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } while (1) { // Receive the response packet. unsigned char answer[32] = {0}; - n = serial_read (device->port, answer, sizeof (answer)); - if (n != sizeof (answer)) { + status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } dc_buffer_append(buffer, answer, sizeof (answer)); // Send the command. - n = serial_write (device->port, command, sizeof (command)); - if (n != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } if (answer[sizeof(answer) - 1] == 0xFF) break; } - serial_set_dtr (device->port, 0); + dc_serial_set_dtr (device->port, 0); return DC_STATUS_SUCCESS; } diff --git a/src/cochran_commander.c b/src/cochran_commander.c index 02ec1cb..735120b 100644 --- a/src/cochran_commander.c +++ b/src/cochran_commander.c @@ -32,11 +32,6 @@ #define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array)) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define COCHRAN_MODEL_COMMANDER_AIR_NITROX 0 #define COCHRAN_MODEL_EMC_14 1 #define COCHRAN_MODEL_EMC_16 2 @@ -92,7 +87,7 @@ typedef struct cochran_device_layout_t { typedef struct cochran_commander_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; const cochran_device_layout_t *layout; unsigned char id[67]; unsigned char fingerprint[6]; @@ -226,33 +221,36 @@ cochran_commander_get_model (cochran_commander_device_t *device) static dc_status_t cochran_commander_serial_setup (cochran_commander_device_t *device) { + dc_status_t status = DC_STATUS_SUCCESS; + // Set the serial communication protocol (9600 8N2, no FC). - int rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (device->base.context, "Failed to set the terminal attributes."); - return DC_STATUS_IO; + return status; } // Set the timeout for receiving data (5000 ms). - if (serial_set_timeout (device->port, 5000) == -1) { + status = dc_serial_set_timeout (device->port, 5000); + if (status != DC_STATUS_SUCCESS) { ERROR (device->base.context, "Failed to set the timeout."); - return DC_STATUS_IO; + return status; } // Wake up DC and trigger heartbeat - serial_set_break(device->port, 1); - serial_sleep(device->port, 16); - serial_set_break(device->port, 0); + dc_serial_set_break(device->port, 1); + dc_serial_sleep(device->port, 16); + dc_serial_set_break(device->port, 0); // Clear old heartbeats - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); // Wait for heartbeat byte before send unsigned char answer = 0; - int n = serial_read(device->port, &answer, 1); - if (n != 1) { + status = dc_serial_read(device->port, &answer, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (device->base.context, "Failed to receive device heartbeat."); - return EXITCODE (n); + return status; } if (answer != 0xAA) { @@ -270,6 +268,7 @@ cochran_commander_packet (cochran_commander_device_t *device, dc_event_progress_ unsigned char answer[], unsigned int asize, int high_speed) { dc_device_t *abstract = (dc_device_t *) device; + dc_status_t status = DC_STATUS_SUCCESS; if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; @@ -279,24 +278,24 @@ cochran_commander_packet (cochran_commander_device_t *device, dc_event_progress_ // has no buffering. for (unsigned int i = 0; i < csize; i++) { // Give the DC time to read the character. - if (i) serial_sleep(device->port, 16); // 16 ms + if (i) dc_serial_sleep(device->port, 16); // 16 ms - unsigned int n = serial_write(device->port, command + i, 1); - if (n != 1) { + status = dc_serial_write(device->port, command + i, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } } if (high_speed) { // Give the DC time to process the command. - serial_sleep(device->port, 45); + dc_serial_sleep(device->port, 45); // Rates are odd, like 806400 for the EMC, 115200 for commander - int rc = serial_configure(device->port, device->layout->baudrate, 8, SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure(device->port, device->layout->baudrate, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to set the high baud rate."); - return DC_STATUS_IO; + return status; } } @@ -308,17 +307,16 @@ cochran_commander_packet (cochran_commander_device_t *device, dc_event_progress_ if (len > 1024) len = 1024; - int n = serial_read (device->port, answer + nbytes, len); - if (n != len) { - ERROR (abstract->context, "Failed to receive data, expected %u," - "read %u.",len, n); - return EXITCODE (n); + status = dc_serial_read (device->port, answer + nbytes, len, NULL); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to receive data."); + return status; } - nbytes += n; + nbytes += len; if (progress) { - progress->current += n; + progress->current += len; device_event_emit (abstract, DC_EVENT_PROGRESS, progress); } } @@ -417,7 +415,7 @@ cochran_commander_read (cochran_commander_device_t *device, dc_event_progress_t return DC_STATUS_UNSUPPORTED; } - serial_sleep(device->port, 800); + dc_serial_sleep(device->port, 800); // set back to 9600 baud rc = cochran_commander_serial_setup(device); @@ -630,10 +628,9 @@ cochran_commander_device_open (dc_device_t **out, dc_context_t *context, const c cochran_commander_device_set_fingerprint((dc_device_t *) device, NULL, 0); // Open the device. - int rc = serial_open (&device->port, device->base.context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, device->base.context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (device->base.context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } @@ -674,7 +671,7 @@ cochran_commander_device_open (dc_device_t **out, dc_context_t *context, const c return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -685,10 +682,12 @@ cochran_commander_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; cochran_commander_device_t *device = (cochran_commander_device_t *) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; diff --git a/src/cressi_edy.c b/src/cressi_edy.c index cfd5f9e..0dbe456 100644 --- a/src/cressi_edy.c +++ b/src/cressi_edy.c @@ -34,11 +34,6 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &cressi_edy_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define MAXRETRIES 4 #define SZ_PACKET 0x80 @@ -60,7 +55,7 @@ typedef struct cressi_edy_layout_t { typedef struct cressi_edy_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; const cressi_edy_layout_t *layout; unsigned char fingerprint[SZ_PAGE / 2]; unsigned int model; @@ -122,6 +117,7 @@ iceil (unsigned int x, unsigned int n) static dc_status_t cressi_edy_packet (cressi_edy_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, int trailer) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; if (device_is_cancelled (abstract)) @@ -129,18 +125,18 @@ cressi_edy_packet (cressi_edy_device_t *device, const unsigned char command[], u for (unsigned int i = 0; i < csize; ++i) { // Send the command to the device. - int n = serial_write (device->port, command + i, 1); - if (n != 1) { + status = dc_serial_write (device->port, command + i, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Receive the echo. unsigned char echo = 0; - n = serial_read (device->port, &echo, 1); - if (n != 1) { + status = dc_serial_read (device->port, &echo, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the echo."); - return EXITCODE (n); + return status; } // Verify the echo. @@ -152,10 +148,10 @@ cressi_edy_packet (cressi_edy_device_t *device, const unsigned char command[], u if (asize) { // Receive the answer of the device. - int n = serial_read (device->port, answer, asize); - if (n != asize) { + status = dc_serial_read (device->port, answer, asize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the trailer of the packet. @@ -182,8 +178,8 @@ cressi_edy_transfer (cressi_edy_device_t *device, const unsigned char command[], return rc; // Delay the next attempt. - serial_sleep (device->port, 300); - serial_flush (device->port, SERIAL_QUEUE_INPUT); + dc_serial_sleep (device->port, 300); + dc_serial_purge (device->port, DC_DIRECTION_INPUT); } return DC_STATUS_SUCCESS; @@ -257,39 +253,43 @@ cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *na memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (1200 8N1). - rc = serial_configure (device->port, 1200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 1200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (1000 ms). - if (serial_set_timeout (device->port, 1000) == -1) { + status = dc_serial_set_timeout (device->port, 1000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } - // Set the DTR and clear the RTS line. - if (serial_set_dtr (device->port, 1) == -1 || - serial_set_rts (device->port, 0) == -1) { - ERROR (context, "Failed to set the DTR/RTS line."); - status = DC_STATUS_IO; + // Set the DTR line. + status = dc_serial_set_dtr (device->port, 1); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to set the DTR line."); + goto error_close; + } + + // Clear the RTS line. + status = dc_serial_set_rts (device->port, 0); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to clear the RTS line."); goto error_close; } // Make sure everything is in a sane state. - serial_sleep(device->port, 300); - serial_flush(device->port, SERIAL_QUEUE_BOTH); + dc_serial_sleep(device->port, 300); + dc_serial_purge(device->port, DC_DIRECTION_ALL); // Send the init commands. cressi_edy_init1 (device); @@ -303,23 +303,22 @@ cressi_edy_device_open (dc_device_t **out, dc_context_t *context, const char *na } // Set the serial communication protocol (4800 8N1). - rc = serial_configure (device->port, 4800, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 4800, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Make sure everything is in a sane state. - serial_sleep(device->port, 300); - serial_flush(device->port, SERIAL_QUEUE_BOTH); + dc_serial_sleep(device->port, 300); + dc_serial_purge(device->port, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -331,13 +330,15 @@ cressi_edy_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; cressi_edy_device_t *device = (cressi_edy_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Send the quit command. cressi_edy_quit (device); // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; diff --git a/src/cressi_leonardo.c b/src/cressi_leonardo.c index 40a6630..b99f999 100644 --- a/src/cressi_leonardo.c +++ b/src/cressi_leonardo.c @@ -34,11 +34,6 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &cressi_leonardo_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define SZ_MEMORY 32000 #define RB_LOGBOOK_BEGIN 0x0100 @@ -52,7 +47,7 @@ typedef struct cressi_leonardo_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; unsigned char fingerprint[5]; } cressi_leonardo_device_t; @@ -93,45 +88,49 @@ cressi_leonardo_device_open (dc_device_t **out, dc_context_t *context, const cha memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (115200 8N1). - rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (1000 ms). - if (serial_set_timeout (device->port, 1000) == -1) { + status = dc_serial_set_timeout (device->port, 1000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } - // Clear the DTR and set the RTS line. - if (serial_set_dtr (device->port, 0) == -1 || - serial_set_rts (device->port, 1) == -1) { - ERROR (context, "Failed to set the DTR/RTS line."); - status = DC_STATUS_IO; + // Clear the DTR line. + status = dc_serial_set_dtr (device->port, 0); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to clear the DTR line."); goto error_close; } - serial_sleep (device->port, 100); - serial_flush (device->port, SERIAL_QUEUE_BOTH); + // Set the RTS line. + status = dc_serial_set_rts (device->port, 1); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to set the RTS line."); + goto error_close; + } + + dc_serial_sleep (device->port, 100); + dc_serial_purge (device->port, DC_DIRECTION_ALL); *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -142,10 +141,12 @@ cressi_leonardo_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; cressi_leonardo_device_t *device = (cressi_leonardo_device_t *) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -170,6 +171,7 @@ cressi_leonardo_device_set_fingerprint (dc_device_t *abstract, const unsigned ch static dc_status_t cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) { + dc_status_t status = DC_STATUS_SUCCESS; cressi_leonardo_device_t *device = (cressi_leonardo_device_t *) abstract; // Erase the current contents of the buffer and @@ -186,18 +188,18 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Send the command header to the dive computer. const unsigned char command[] = {0x7B, 0x31, 0x32, 0x33, 0x44, 0x42, 0x41, 0x7d}; - int n = serial_write (device->port, command, sizeof (command)); - if (n != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Receive the header packet. unsigned char header[7] = {0}; - n = serial_read (device->port, header, sizeof (header)); - if (n != sizeof (header)) { + status = dc_serial_read (device->port, header, sizeof (header), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the header packet. @@ -215,8 +217,9 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) unsigned int len = 1024; // Increase the packet size if more data is immediately available. - int available = serial_get_received (device->port); - if (available > len) + size_t available = 0; + status = dc_serial_get_available (device->port, &available); + if (status == DC_STATUS_SUCCESS && available > len) len = available; // Limit the packet size to the total size. @@ -224,10 +227,10 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) len = SZ_MEMORY - nbytes; // Read the packet. - n = serial_read (device->port, data + nbytes, len); - if (n != len) { + status = dc_serial_read (device->port, data + nbytes, len, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Update and emit a progress event. @@ -239,10 +242,10 @@ cressi_leonardo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Receive the trailer packet. unsigned char trailer[4] = {0}; - n = serial_read (device->port, trailer, sizeof (trailer)); - if (n != sizeof (trailer)) { + status = dc_serial_read (device->port, trailer, sizeof (trailer), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Convert to a binary checksum. diff --git a/src/custom_serial.c b/src/custom_serial.c deleted file mode 100644 index a6af432..0000000 --- a/src/custom_serial.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * libdivecomputer - * - * Copyright (C) 2015 Claudiu Olteanu - * base on code that is Copyright (C) 2008 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 -#include - -#include "context-private.h" - -const dc_serial_operations_t native_serial_ops = { - .open = serial_open, - .close = serial_close, - .read = serial_read, - .write = serial_write, - .flush = serial_flush, - .get_received = serial_get_received, - .get_transmitted = serial_get_transmitted, - .set_timeout = serial_set_timeout -}; - - -void -dc_serial_init(dc_serial_t *device, void *data, const dc_serial_operations_t *ops) -{ - memset(device, 0, sizeof (*device)); - device->data = data; - device->ops = ops; -} - - -dc_status_t -dc_serial_native_open(dc_serial_t **out, dc_context_t *context, const char *devname) -{ - if (out == NULL) - return DC_STATUS_INVALIDARGS; - - // Allocate memory. - dc_serial_t *serial_device = (dc_serial_t *) malloc (sizeof (dc_serial_t)); - - if (serial_device == NULL) { - ERROR (context, "Failed to allocate memory."); - return DC_STATUS_NOMEMORY; - } - - // Initialize data and function pointers - dc_serial_init(serial_device, NULL, &native_serial_ops); - - // Open the serial device. - int rc = serial_open (&serial_device->port, context, devname); - if (rc == -1) { - ERROR (context, "Failed to open the serial port."); - free (serial_device); - return DC_STATUS_IO; - } - - // Set the type of the device - serial_device->type = DC_TRANSPORT_SERIAL; - - *out = serial_device; - - return DC_STATUS_SUCCESS; -} diff --git a/src/descriptor.c b/src/descriptor.c index b774062..39b3161 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -37,6 +37,7 @@ struct dc_descriptor_t { const char *product; dc_family_t type; unsigned int model; + unsigned int serial; }; /* @@ -115,12 +116,15 @@ static const dc_descriptor_t g_descriptors[] = { #endif /* Scubapro/Uwatec Meridian */ {"Scubapro", "Meridian", DC_FAMILY_UWATEC_MERIDIAN, 0x20}, + {"Scubapro", "Mantis", DC_FAMILY_UWATEC_MERIDIAN, 0x20}, {"Scubapro", "Chromis", DC_FAMILY_UWATEC_MERIDIAN, 0x24}, + {"Scubapro", "Mantis 2", DC_FAMILY_UWATEC_MERIDIAN, 0x26}, /* Reefnet */ {"Reefnet", "Sensus", DC_FAMILY_REEFNET_SENSUS, 1}, {"Reefnet", "Sensus Pro", DC_FAMILY_REEFNET_SENSUSPRO, 2}, {"Reefnet", "Sensus Ultra", DC_FAMILY_REEFNET_SENSUSULTRA, 3}, /* Oceanic VT Pro */ + {"Aeris", "500 AI", DC_FAMILY_OCEANIC_VTPRO, 0x4151}, {"Oceanic", "Versa Pro", DC_FAMILY_OCEANIC_VTPRO, 0x4155}, {"Aeris", "Atmos 2", DC_FAMILY_OCEANIC_VTPRO, 0x4158}, {"Oceanic", "Pro Plus 2", DC_FAMILY_OCEANIC_VTPRO, 0x4159}, @@ -185,9 +189,11 @@ static const dc_descriptor_t g_descriptors[] = { {"Aeris", "A300CS", DC_FAMILY_OCEANIC_ATOM2, 0x454C}, {"Beuchat", "Mundial 3", DC_FAMILY_OCEANIC_ATOM2, 0x4550}, {"Oceanic", "F11", DC_FAMILY_OCEANIC_ATOM2, 0x4554}, + {"Sherwood", "Vision", DC_FAMILY_OCEANIC_ATOM2, 0x4556}, {"Oceanic", "VTX", DC_FAMILY_OCEANIC_ATOM2, 0x4557}, {"Aqualung", "i300", DC_FAMILY_OCEANIC_ATOM2, 0x4559}, {"Aqualung", "i450T", DC_FAMILY_OCEANIC_ATOM2, 0x4641}, + {"Aqualung", "i550T", DC_FAMILY_OCEANIC_ATOM2, 0x4642}, /* Mares Nemo */ {"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0}, {"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0}, @@ -221,11 +227,16 @@ static const dc_descriptor_t g_descriptors[] = { {"Heinrichs Weikamp", "OSTC 2C", DC_FAMILY_HW_OSTC, 3}, {"Heinrichs Weikamp", "Frog", DC_FAMILY_HW_FROG, 0}, {"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x11}, + {"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x13}, + {"Heinrichs Weikamp", "OSTC 2", DC_FAMILY_HW_OSTC3, 0x1B}, {"Heinrichs Weikamp", "OSTC 3", DC_FAMILY_HW_OSTC3, 0x0A}, - {"Heinrichs Weikamp", "OSTC 3", DC_FAMILY_HW_OSTC3, 0x1A}, + {"Heinrichs Weikamp", "OSTC 3+", DC_FAMILY_HW_OSTC3, 0x13}, + {"Heinrichs Weikamp", "OSTC 3+", DC_FAMILY_HW_OSTC3, 0x1A}, {"Heinrichs Weikamp", "OSTC 4", DC_FAMILY_HW_OSTC3, 0x3B}, {"Heinrichs Weikamp", "OSTC cR", DC_FAMILY_HW_OSTC3, 0x05}, + {"Heinrichs Weikamp", "OSTC cR", DC_FAMILY_HW_OSTC3, 0x07}, {"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 0x12}, + {"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 0x13}, /* Cressi Edy */ {"Tusa", "IQ-700", DC_FAMILY_CRESSI_EDY, 0x05}, {"Cressi", "Edy", DC_FAMILY_CRESSI_EDY, 0x08}, @@ -379,6 +390,15 @@ dc_descriptor_get_model (dc_descriptor_t *descriptor) return descriptor->model; } +unsigned int +dc_descriptor_get_serial (dc_descriptor_t *descriptor) +{ + if (descriptor == NULL) + return 0; + + return descriptor->serial; +} + dc_transport_t dc_descriptor_get_transport (dc_descriptor_t *descriptor) { diff --git a/src/device.c b/src/device.c index bf8820c..526ded1 100644 --- a/src/device.c +++ b/src/device.c @@ -130,7 +130,7 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr rc = reefnet_sensusultra_device_open (&device, context, name); break; case DC_FAMILY_OCEANIC_VTPRO: - rc = oceanic_vtpro_device_open (&device, context, name); + rc = oceanic_vtpro_device_open2 (&device, context, name, dc_descriptor_get_model (descriptor)); break; case DC_FAMILY_OCEANIC_VEO250: rc = oceanic_veo250_device_open (&device, context, name); diff --git a/src/diverite_nitekq.c b/src/diverite_nitekq.c index a873424..30060cd 100644 --- a/src/diverite_nitekq.c +++ b/src/diverite_nitekq.c @@ -33,11 +33,6 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &diverite_nitekq_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define KEEPALIVE 0x3E // '<' #define BLOCK 0x42 // 'B' #define DISCONNECT 0x44 // 'D' @@ -57,7 +52,7 @@ typedef struct diverite_nitekq_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; unsigned char version[32]; unsigned char fingerprint[SZ_LOGBOOK]; } diverite_nitekq_device_t; @@ -82,6 +77,7 @@ static const dc_device_vtable_t diverite_nitekq_device_vtable = { static dc_status_t diverite_nitekq_send (diverite_nitekq_device_t *device, unsigned char cmd) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; if (device_is_cancelled (abstract)) @@ -89,10 +85,10 @@ diverite_nitekq_send (diverite_nitekq_device_t *device, unsigned char cmd) // Send the command. unsigned char command[] = {cmd}; - int n = serial_write (device->port, command, sizeof (command)); - if (n != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } return DC_STATUS_SUCCESS; @@ -102,21 +98,22 @@ diverite_nitekq_send (diverite_nitekq_device_t *device, unsigned char cmd) static dc_status_t diverite_nitekq_receive (diverite_nitekq_device_t *device, unsigned char data[], unsigned int size) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Read the answer. - int n = serial_read (device->port, data, size); - if (n != size) { + status = dc_serial_read (device->port, data, size, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Read the checksum. unsigned char checksum[2] = {0}; - n = serial_read (device->port, checksum, sizeof (checksum)); - if (n != sizeof (checksum)) { + status = dc_serial_read (device->port, checksum, sizeof (checksum), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the checksum."); - return EXITCODE (n); + return status; } return DC_STATUS_SUCCESS; @@ -126,21 +123,22 @@ diverite_nitekq_receive (diverite_nitekq_device_t *device, unsigned char data[], static dc_status_t diverite_nitekq_handshake (diverite_nitekq_device_t *device) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Send the command. unsigned char command[] = {HANDSHAKE}; - int n = serial_write (device->port, command, sizeof (command)); - if (n != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Read the answer. - n = serial_read (device->port, device->version, sizeof (device->version)); - if (n != sizeof (device->version)) { + status = dc_serial_read (device->port, device->version, sizeof (device->version), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } return DC_STATUS_SUCCESS; @@ -168,31 +166,29 @@ diverite_nitekq_device_open (dc_device_t **out, dc_context_t *context, const cha memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (9600 8N1). - rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (1000ms). - if (serial_set_timeout (device->port, 1000) == -1) { + status = dc_serial_set_timeout (device->port, 1000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Make sure everything is in a sane state. - serial_sleep (device->port, 100); - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_sleep (device->port, 100); + dc_serial_purge (device->port, DC_DIRECTION_ALL); // Perform the handshaking. status = diverite_nitekq_handshake (device); @@ -206,7 +202,7 @@ diverite_nitekq_device_open (dc_device_t **out, dc_context_t *context, const cha return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -218,13 +214,15 @@ diverite_nitekq_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; diverite_nitekq_device_t *device = (diverite_nitekq_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Disconnect. diverite_nitekq_send (device, DISCONNECT); // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; diff --git a/src/divesystem_idive.c b/src/divesystem_idive.c index e48e47b..75a2dbe 100644 --- a/src/divesystem_idive.c +++ b/src/divesystem_idive.c @@ -32,11 +32,6 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &divesystem_idive_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define IX3M_EASY 0x22 #define IX3M_DEEP 0x23 #define IX3M_TEC 0x24 @@ -67,7 +62,7 @@ typedef struct divesystem_idive_commands_t { typedef struct divesystem_idive_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; unsigned char fingerprint[4]; unsigned int model; } divesystem_idive_device_t; @@ -130,38 +125,36 @@ divesystem_idive_device_open2 (dc_device_t **out, dc_context_t *context, const c device->model = model; // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (115200 8N1). - rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (1000ms). - if (serial_set_timeout (device->port, 1000) == -1) { + status = dc_serial_set_timeout (device->port, 1000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Make sure everything is in a sane state. - serial_sleep (device->port, 300); - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_sleep (device->port, 300); + dc_serial_purge (device->port, DC_DIRECTION_ALL); *out = (dc_device_t *) device; return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -173,10 +166,12 @@ divesystem_idive_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; divesystem_idive_device_t *device = (divesystem_idive_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -203,6 +198,7 @@ divesystem_idive_device_set_fingerprint (dc_device_t *abstract, const unsigned c static dc_status_t divesystem_idive_send (divesystem_idive_device_t *device, const unsigned char command[], unsigned int csize) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; unsigned char packet[MAXPACKET + 4]; unsigned short crc = 0; @@ -222,10 +218,10 @@ divesystem_idive_send (divesystem_idive_device_t *device, const unsigned char co packet[csize + 3] = (crc ) & 0xFF; // Send the data packet. - int n = serial_write (device->port, packet, csize + 4); - if (n != csize + 4) { + status = dc_serial_write (device->port, packet, csize + 4, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } return DC_STATUS_SUCCESS; @@ -235,9 +231,9 @@ divesystem_idive_send (divesystem_idive_device_t *device, const unsigned char co static dc_status_t divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answer[], unsigned int *asize) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; unsigned char packet[MAXPACKET + 4]; - int n = 0; if (asize == NULL || *asize < MAXPACKET) { ERROR (abstract->context, "Invalid arguments."); @@ -246,10 +242,10 @@ divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answe // Read the packet start byte. while (1) { - n = serial_read (device->port, packet + 0, 1); - if (n != 1) { + status = dc_serial_read (device->port, packet + 0, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet start byte."); - return EXITCODE (n); + return status; } if (packet[0] == START) @@ -257,10 +253,10 @@ divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answe } // Read the packet length. - n = serial_read (device->port, packet + 1, 1); - if (n != 1) { + status = dc_serial_read (device->port, packet + 1, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet length."); - return EXITCODE (n); + return status; } unsigned int len = packet[1]; @@ -270,10 +266,10 @@ divesystem_idive_receive (divesystem_idive_device_t *device, unsigned char answe } // Read the packet payload and checksum. - n = serial_read (device->port, packet + 2, len + 2); - if (n != len + 2) { + status = dc_serial_read (device->port, packet + 2, len + 2, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet payload and checksum."); - return EXITCODE (n); + return status; } // Verify the checksum. @@ -346,7 +342,7 @@ divesystem_idive_transfer (divesystem_idive_device_t *device, const unsigned cha return DC_STATUS_PROTOCOL; // Delay the next attempt. - serial_sleep(device->port, 100); + dc_serial_sleep(device->port, 100); } // Verify the length of the packet. diff --git a/src/hw_frog.c b/src/hw_frog.c index 511052c..0ba5342 100644 --- a/src/hw_frog.c +++ b/src/hw_frog.c @@ -33,11 +33,6 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &hw_frog_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define SZ_DISPLAY 15 #define SZ_CUSTOMTEXT 13 #define SZ_VERSION (SZ_CUSTOMTEXT + 4) @@ -61,7 +56,7 @@ typedef struct hw_frog_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; unsigned char fingerprint[5]; } hw_frog_device_t; @@ -110,6 +105,7 @@ hw_frog_transfer (hw_frog_device_t *device, unsigned char output[], unsigned int osize) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; if (device_is_cancelled (abstract)) @@ -117,19 +113,19 @@ hw_frog_transfer (hw_frog_device_t *device, // Send the command. unsigned char command[1] = {cmd}; - int n = serial_write (device->port, command, sizeof (command)); - if (n != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } if (cmd != INIT && cmd != HEADER) { // Read the echo. unsigned char answer[1] = {0}; - n = serial_read (device->port, answer, sizeof (answer)); - if (n != sizeof (answer)) { + status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the echo."); - return EXITCODE (n); + return status; } // Verify the echo. @@ -141,10 +137,10 @@ hw_frog_transfer (hw_frog_device_t *device, if (input) { // Send the input data packet. - n = serial_write (device->port, input, isize); - if (n != isize) { + status = dc_serial_write (device->port, input, isize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the data packet."); - return EXITCODE (n); + return status; } } @@ -155,8 +151,9 @@ hw_frog_transfer (hw_frog_device_t *device, unsigned int len = 1024; // Increase the packet size if more data is immediately available. - int available = serial_get_received (device->port); - if (available > len) + size_t available = 0; + status = dc_serial_get_available (device->port, &available); + if (status == DC_STATUS_SUCCESS && available > len) len = available; // Limit the packet size to the total size. @@ -164,10 +161,10 @@ hw_frog_transfer (hw_frog_device_t *device, len = osize - nbytes; // Read the packet. - n = serial_read (device->port, output + nbytes, len); - if (n != len) { + status = dc_serial_read (device->port, output + nbytes, len, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Update and emit a progress event. @@ -183,10 +180,10 @@ hw_frog_transfer (hw_frog_device_t *device, if (cmd != EXIT) { // Read the ready byte. unsigned char answer[1] = {0}; - n = serial_read (device->port, answer, sizeof (answer)); - if (n != sizeof (answer)) { + status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + if (status != sizeof (answer)) { ERROR (abstract->context, "Failed to receive the ready byte."); - return EXITCODE (n); + return status; } // Verify the ready byte. @@ -221,31 +218,29 @@ hw_frog_device_open (dc_device_t **out, dc_context_t *context, const char *name) memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (115200 8N1). - rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (3000ms). - if (serial_set_timeout (device->port, 3000) == -1) { + status = dc_serial_set_timeout (device->port, 3000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Make sure everything is in a sane state. - serial_sleep (device->port, 300); - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_sleep (device->port, 300); + dc_serial_purge (device->port, DC_DIRECTION_ALL); // Send the init command. status = hw_frog_transfer (device, NULL, INIT, NULL, 0, NULL, 0); @@ -259,7 +254,7 @@ hw_frog_device_open (dc_device_t **out, dc_context_t *context, const char *name) return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -281,8 +276,9 @@ hw_frog_device_close (dc_device_t *abstract) } // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; diff --git a/src/hw_ostc.c b/src/hw_ostc.c index 6a6c3d7..1185e81 100644 --- a/src/hw_ostc.c +++ b/src/hw_ostc.c @@ -33,11 +33,6 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define C_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) #define MAXRETRIES 9 @@ -64,7 +59,7 @@ typedef struct hw_ostc_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; unsigned char fingerprint[5]; } hw_ostc_device_t; @@ -93,23 +88,24 @@ static const dc_device_vtable_t hw_ostc_device_vtable = { static dc_status_t hw_ostc_send (hw_ostc_device_t *device, unsigned char cmd, unsigned int echo) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Send the command. unsigned char command[1] = {cmd}; - int n = serial_write (device->port, command, sizeof (command)); - if (n != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } if (echo) { // Read the echo. unsigned char answer[1] = {0}; - n = serial_read (device->port, answer, sizeof (answer)); - if (n != sizeof (answer)) { + status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the echo."); - return EXITCODE (n); + return status; } // Verify the echo. @@ -144,38 +140,36 @@ hw_ostc_device_open (dc_device_t **out, dc_context_t *context, const char *name) memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (115200 8N1). - rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data. - if (serial_set_timeout (device->port, 4000) == -1) { + status = dc_serial_set_timeout (device->port, 4000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Make sure everything is in a sane state. - serial_sleep (device->port, 100); - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_sleep (device->port, 100); + dc_serial_purge (device->port, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -187,10 +181,12 @@ hw_ostc_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; hw_ostc_device_t *device = (hw_ostc_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -217,6 +213,7 @@ hw_ostc_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[ static dc_status_t hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) { + dc_status_t status = DC_STATUS_SUCCESS; hw_ostc_device_t *device = (hw_ostc_device_t*) abstract; // Erase the current contents of the buffer. @@ -232,18 +229,18 @@ hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Send the command. unsigned char command[1] = {'a'}; - int rc = serial_write (device->port, command, sizeof (command)); - if (rc != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (rc); + return status; } // Read the header. unsigned char header[SZ_HEADER] = {0}; - int n = serial_read (device->port, header, sizeof (header)); - if (n != sizeof (header)) { + status = dc_serial_read (device->port, header, sizeof (header), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the header."); - return EXITCODE (n); + return status; } // Verify the header. @@ -285,8 +282,9 @@ hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) unsigned int len = 1024; // Increase the packet size if more data is immediately available. - int available = serial_get_received (device->port); - if (available > len) + size_t available = 0; + status = dc_serial_get_available (device->port, &available); + if (status == DC_STATUS_SUCCESS && available > len) len = available; // Limit the packet size to the total size. @@ -294,10 +292,10 @@ hw_ostc_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) len = size - nbytes; // Read the packet. - int n = serial_read (device->port, data + nbytes, len); - if (n != len) { + status = dc_serial_read (device->port, data + nbytes, len, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Update and emit a progress event. @@ -351,6 +349,7 @@ hw_ostc_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void dc_status_t hw_ostc_device_md2hash (dc_device_t *abstract, unsigned char data[], unsigned int size) { + dc_status_t status = DC_STATUS_SUCCESS; hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; if (!ISINSTANCE (abstract)) @@ -367,10 +366,10 @@ hw_ostc_device_md2hash (dc_device_t *abstract, unsigned char data[], unsigned in return rc; // Read the answer. - int n = serial_read (device->port, data, SZ_MD2HASH); - if (n != SZ_MD2HASH) { + status = dc_serial_read (device->port, data, SZ_MD2HASH, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } return DC_STATUS_SUCCESS; @@ -380,6 +379,7 @@ hw_ostc_device_md2hash (dc_device_t *abstract, unsigned char data[], unsigned in dc_status_t hw_ostc_device_clock (dc_device_t *abstract, const dc_datetime_t *datetime) { + dc_status_t status = DC_STATUS_SUCCESS; hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; if (!ISINSTANCE (abstract)) @@ -399,10 +399,10 @@ hw_ostc_device_clock (dc_device_t *abstract, const dc_datetime_t *datetime) unsigned char packet[6] = { datetime->hour, datetime->minute, datetime->second, datetime->month, datetime->day, datetime->year - 2000}; - int n = serial_write (device->port, packet, sizeof (packet)); - if (n != sizeof (packet)) { + status = dc_serial_write (device->port, packet, sizeof (packet), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the data packet."); - return EXITCODE (n); + return status; } return DC_STATUS_SUCCESS; @@ -412,6 +412,7 @@ hw_ostc_device_clock (dc_device_t *abstract, const dc_datetime_t *datetime) dc_status_t hw_ostc_device_eeprom_read (dc_device_t *abstract, unsigned int bank, unsigned char data[], unsigned int size) { + dc_status_t status = DC_STATUS_SUCCESS; hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; if (!ISINSTANCE (abstract)) @@ -434,10 +435,10 @@ hw_ostc_device_eeprom_read (dc_device_t *abstract, unsigned int bank, unsigned c return rc; // Read the answer. - int n = serial_read (device->port, data, SZ_EEPROM); - if (n != SZ_EEPROM) { + status = dc_serial_read (device->port, data, SZ_EEPROM, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } return DC_STATUS_SUCCESS; @@ -499,6 +500,7 @@ hw_ostc_device_reset (dc_device_t *abstract) dc_status_t hw_ostc_device_screenshot (dc_device_t *abstract, dc_buffer_t *buffer, hw_ostc_format_t format) { + dc_status_t status = DC_STATUS_SUCCESS; hw_ostc_device_t *device = (hw_ostc_device_t *) abstract; if (!ISINSTANCE (abstract)) @@ -554,13 +556,13 @@ hw_ostc_device_screenshot (dc_device_t *abstract, dc_buffer_t *buffer, hw_ostc_f unsigned int npixels = 0; while (npixels < WIDTH * HEIGHT) { unsigned char raw[3] = {0}; - int n = serial_read (device->port, raw, 1); - if (n != 1) { + status = dc_serial_read (device->port, raw, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet."); - return EXITCODE (n); + return status; } - unsigned int nbytes = n; + unsigned int nbytes = 1; unsigned int count = raw[0]; if ((count & 0x80) == 0x00) { // Black pixel. @@ -572,13 +574,13 @@ hw_ostc_device_screenshot (dc_device_t *abstract, dc_buffer_t *buffer, hw_ostc_f count &= 0x3F; } else { // Color pixel. - n = serial_read (device->port, raw + 1, 2); - if (n != 2) { + status = dc_serial_read (device->port, raw + 1, 2, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet."); - return EXITCODE (n); + return status; } - nbytes += n; + nbytes += 2; count &= 0x3F; } count++; @@ -767,22 +769,23 @@ hw_ostc_firmware_readfile (hw_ostc_firmware_t *firmware, dc_context_t *context, static dc_status_t hw_ostc_firmware_setup_internal (hw_ostc_device_t *device) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Send the command. unsigned char command[1] = {0xC1}; - int n = serial_write (device->port, command, sizeof (command)); - if (n != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Read the response. unsigned char answer[2] = {0}; - n = serial_read (device->port, answer, sizeof (answer)); - if (n != sizeof (answer)) { + status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the response."); - return EXITCODE (n); + return status; } // Verify the response. @@ -818,21 +821,22 @@ hw_ostc_firmware_setup (hw_ostc_device_t *device, unsigned int maxretries) static dc_status_t hw_ostc_firmware_write_internal (hw_ostc_device_t *device, unsigned char *data, unsigned int size) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Send the packet. - int n = serial_write (device->port, data, size); - if (n != size) { + status = dc_serial_write (device->port, data, size, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the packet."); - return EXITCODE (n); + return status; } // Read the response. unsigned char answer[1] = {0}; - n = serial_read (device->port, answer, sizeof (answer)); - if (n != sizeof (answer)) { + status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the response."); - return EXITCODE (n); + return status; } // Verify the response. @@ -901,16 +905,17 @@ hw_ostc_device_fwupdate (dc_device_t *abstract, const char *filename) // bootloader needs to be send repeatedly, until the response packet is // received. Thus the time between each two attempts is directly controlled // by the timeout value. - serial_set_timeout (device->port, 300); + dc_serial_set_timeout (device->port, 300); // Setup the bootloader. const unsigned int baudrates[] = {19200, 115200}; for (unsigned int i = 0; i < C_ARRAY_SIZE(baudrates); ++i) { // Adjust the baudrate. - if (serial_configure (device->port, baudrates[i], 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE) == -1) { + rc = dc_serial_configure (device->port, baudrates[i], 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to set the terminal attributes."); free (firmware); - return DC_STATUS_IO; + return rc; } // Try to setup the bootloader. @@ -926,7 +931,7 @@ hw_ostc_device_fwupdate (dc_device_t *abstract, const char *filename) } // Increase the timeout again. - serial_set_timeout (device->port, 1000); + dc_serial_set_timeout (device->port, 1000); // Enable progress notifications. dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index f12287b..acf6012 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -39,15 +39,11 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc3_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define SZ_DISPLAY 16 #define SZ_CUSTOMTEXT 60 #define SZ_VERSION (SZ_CUSTOMTEXT + 4) #define SZ_HARDWARE 1 +#define SZ_HARDWARE2 5 #define SZ_MEMORY 0x400000 #define SZ_CONFIG 4 #define SZ_FWINFO 4 @@ -65,6 +61,7 @@ #define S_READY 0x4C #define READY 0x4D #define S_UPGRADE 0x50 +#define HARDWARE2 0x60 #define HEADER 0x61 #define CLOCK 0x62 #define CUSTOMTEXT 0x63 @@ -99,8 +96,10 @@ typedef enum hw_ostc3_state_t { typedef struct hw_ostc3_device_t { dc_device_t base; - dc_serial_t *serial; + dc_serial_t *port; unsigned int hardware; + unsigned int feature; + unsigned int model; unsigned char fingerprint[5]; hw_ostc3_state_t state; } hw_ostc3_device_t; @@ -189,6 +188,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, unsigned int delay) { dc_device_t *abstract = (dc_device_t *) device; + dc_status_t status = DC_STATUS_SUCCESS; if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; @@ -198,18 +198,18 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, // Send the command. unsigned char command[1] = {cmd}; - int n = device->serial->ops->write (device->serial->port, command, sizeof (command)); - if (n != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Read the echo. unsigned char echo[1] = {0}; - n = device->serial->ops->read (device->serial->port, echo, sizeof (echo)); - if (n != sizeof (echo)) { + status = dc_serial_read (device->port, echo, sizeof (echo), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the echo."); - return EXITCODE (n); + return status; } // Verify the echo. @@ -235,10 +235,10 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, len = isize - nbytes; // Write the packet. - n = device->serial->ops->write (device->serial->port, input + nbytes, len); - if (n != len) { + status = dc_serial_write (device->port, input + nbytes, len, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the data packet."); - return EXITCODE (n); + return status; } // Update and emit a progress event. @@ -258,8 +258,9 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, unsigned int len = 1024; // Increase the packet size if more data is immediately available. - int available = device->serial->ops->get_received (device->serial->port); - if (available > len) + size_t available = 0; + status = dc_serial_get_available (device->port, &available); + if (status == DC_STATUS_SUCCESS && available > len) len = available; // Limit the packet size to the total size. @@ -267,10 +268,10 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, len = osize - nbytes; // Read the packet. - n = device->serial->ops->read (device->serial->port, output + nbytes, len); - if (n != len) { + status = dc_serial_read (device->port, output + nbytes, len, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Update and emit a progress event. @@ -286,20 +287,22 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, if (delay) { unsigned int count = delay / 100; for (unsigned int i = 0; i < count; ++i) { - if (device->serial->ops->get_received (device->serial->port) > 0) + size_t available = 0; + status = dc_serial_get_available (device->port, &available); + if (status == DC_STATUS_SUCCESS && available > 0) break; - serial_sleep (device->serial->port, 100); + dc_serial_sleep (device->port, 100); } } if (cmd != EXIT) { // Read the ready byte. unsigned char answer[1] = {0}; - n = device->serial->ops->read (device->serial->port, answer, sizeof (answer)); - if (n != sizeof (answer)) { + status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the ready byte."); - return EXITCODE (n); + return status; } // Verify the ready byte. @@ -330,36 +333,37 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name } // Set the default values. - device->serial = NULL; + device->port = NULL; device->hardware = INVALID; + device->feature = 0; + device->model = 0; memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - int rc = dc_serial_native_open (&device->serial, context, name); - if (rc != DC_STATUS_SUCCESS) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (115200 8N1). - rc = serial_configure (device->serial->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (3000ms). - if (serial_set_timeout (device->serial->port, 3000) == -1) { + status = dc_serial_set_timeout (device->port, 3000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); status = DC_STATUS_IO; goto error_close; } // Make sure everything is in a sane state. - serial_sleep (device->serial->port, 300); - device->serial->ops->flush (device->serial->port, SERIAL_QUEUE_BOTH); + dc_serial_sleep (device->port, 300); + dc_serial_purge (device->port, DC_DIRECTION_ALL); device->state = OPEN; @@ -368,7 +372,7 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, const char *name return DC_STATUS_SUCCESS; error_close: - device->serial->ops->close (device->serial->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -376,12 +380,12 @@ error_free: dc_status_t -hw_ostc3_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial_t *serial) +hw_ostc3_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial_t *port) { dc_status_t status = DC_STATUS_SUCCESS; hw_ostc3_device_t *device = NULL; - if (out == NULL || serial == NULL || serial->port == NULL) + if (out == NULL || port == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. @@ -396,12 +400,13 @@ hw_ostc3_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Set the serial reference - device->serial = serial; + device->port = port; - if (serial->type == DC_TRANSPORT_SERIAL) { + if (1) { +// if (port->type == DC_TRANSPORT_SERIAL) { // Set the serial communication protocol (115200 8N1). - int rc = serial_configure (device->serial->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, 1, DC_FLOWCONTROL_NONE); + if (status == DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); status = DC_STATUS_IO; goto error_close; @@ -409,15 +414,15 @@ hw_ostc3_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial } // Set the timeout for receiving data (3000ms). - if (device->serial->ops->set_timeout (device->serial->port, 3000) == -1) { + status = dc_serial_set_timeout (device->port, 3000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Make sure everything is in a sane state. - serial_sleep (device->serial->port, 300); - device->serial->ops->flush (device->serial->port, SERIAL_QUEUE_BOTH); + dc_serial_sleep (device->port, 300); + dc_serial_purge (device->port, DC_DIRECTION_ALL); device->state = OPEN; @@ -426,13 +431,40 @@ hw_ostc3_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial return DC_STATUS_SUCCESS; error_close: - device->serial->ops->close (device->serial->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; } +static dc_status_t +hw_ostc3_device_id (hw_ostc3_device_t *device, unsigned char data[], unsigned int size) +{ + dc_status_t status = DC_STATUS_SUCCESS; + + if (size != SZ_HARDWARE && size != SZ_HARDWARE2) + return DC_STATUS_INVALIDARGS; + + // Send the command. + unsigned char hardware[SZ_HARDWARE2] = {0}; + status = hw_ostc3_transfer (device, NULL, HARDWARE2, NULL, 0, hardware, SZ_HARDWARE2, NODELAY); + if (status == DC_STATUS_UNSUPPORTED) { + status = hw_ostc3_transfer (device, NULL, HARDWARE, NULL, 0, hardware + 1, SZ_HARDWARE, NODELAY); + } + if (status != DC_STATUS_SUCCESS) + return status; + + if (size == SZ_HARDWARE2) { + memcpy (data, hardware, SZ_HARDWARE2); + } else { + memcpy (data, hardware + 1, SZ_HARDWARE); + } + + return DC_STATUS_SUCCESS; +} + + static dc_status_t hw_ostc3_device_init_download (hw_ostc3_device_t *device) { @@ -455,28 +487,28 @@ hw_ostc3_device_init_download (hw_ostc3_device_t *device) static dc_status_t hw_ostc3_device_init_service (hw_ostc3_device_t *device) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; dc_context_t *context = (abstract ? abstract->context : NULL); unsigned char command[] = {0xAA, 0xAB, 0xCD, 0xEF}; unsigned char output[5]; - int n = 0; // We cant use hw_ostc3_transfer here, due to the different echos - n = device->serial->ops->write (device->serial->port, command, sizeof (command)); - if (n != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Give the device some time to enter service mode - serial_sleep (device->serial->port, 100); + dc_serial_sleep (device->port, 100); // Read the response - n = device->serial->ops->read (device->serial->port, output, sizeof (output)); - if (n != sizeof (output)) { + status = dc_serial_read (device->port, output, sizeof (output), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to receive the echo."); - return EXITCODE (n); + return status; } // Verify the response to service mode @@ -528,15 +560,17 @@ hw_ostc3_device_init (hw_ostc3_device_t *device, hw_ostc3_state_t state) return DC_STATUS_SUCCESS; // Read the hardware descriptor. - unsigned char hardware[SZ_HARDWARE] = {UNKNOWN}; - rc = hw_ostc3_transfer (device, NULL, HARDWARE, NULL, 0, hardware, sizeof(hardware), NODELAY); + unsigned char hardware[SZ_HARDWARE2] = {0, UNKNOWN}; + rc = hw_ostc3_device_id (device, hardware, sizeof(hardware)); if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) { ERROR (abstract->context, "Failed to read the hardware descriptor."); return rc; } // Cache the descriptor. - device->hardware = hardware[0]; + device->hardware = array_uint16_be(hardware + 0); + device->feature = array_uint16_be(hardware + 2); + device->model = hardware[4]; return DC_STATUS_SUCCESS; } @@ -554,14 +588,13 @@ hw_ostc3_device_close (dc_device_t *abstract) rc = hw_ostc3_transfer (device, NULL, EXIT, NULL, 0, NULL, 0, NODELAY); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - device->serial->ops->close (device->serial->port); - dc_status_set_error(&status, rc); } } // Close the device. - if (device->serial->ops->close (device->serial->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -617,7 +650,7 @@ hw_ostc3_device_hardware (dc_device_t *abstract, unsigned char data[], unsigned if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; - if (size != SZ_HARDWARE) + if (size != SZ_HARDWARE && size != SZ_HARDWARE2) return DC_STATUS_INVALIDARGS; dc_status_t rc = hw_ostc3_device_init (device, DOWNLOAD); @@ -625,7 +658,7 @@ hw_ostc3_device_hardware (dc_device_t *abstract, unsigned char data[], unsigned return rc; // Send the command. - rc = hw_ostc3_transfer (device, NULL, HARDWARE, NULL, 0, data, size, NODELAY); + rc = hw_ostc3_device_id (device, data, size); if (rc != DC_STATUS_SUCCESS) return rc; @@ -657,7 +690,11 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi // Emit a device info event. dc_event_devinfo_t devinfo; - devinfo.firmware = array_uint16_be (id + 2); + if (device->hardware == OSTC4) { + devinfo.firmware = array_uint16_le (id + 2); + } else { + devinfo.firmware = array_uint16_be (id + 2); + } devinfo.serial = array_uint16_le (id + 0); if (device->hardware != UNKNOWN) { devinfo.model = device->hardware; diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index 1604c12..e67099f 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -68,6 +68,8 @@ #define OSTC3_ZHL16 0 #define OSTC3_ZHL16_GF 1 +#define OSTC4 0x3B + #define UNSUPPORTED 0xFFFFFFFF typedef struct hw_ostc_sample_info_t { @@ -87,7 +89,7 @@ typedef struct hw_ostc_layout_t { unsigned int temperature; unsigned int battery; unsigned int desat; - unsigned int fw_version; + unsigned int firmware; unsigned int deco_info1; unsigned int deco_info2; unsigned int decomode; @@ -100,7 +102,8 @@ typedef struct hw_ostc_gasmix_t { typedef struct hw_ostc_parser_t { dc_parser_t base; - unsigned int frog; + unsigned int hwos; + unsigned int model; unsigned int serial; // Cached fields. unsigned int cached; @@ -139,7 +142,7 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc = { 13, /* temperature */ 34, /* battery volt after dive */ 17, /* desat */ - 32, /* fw_version */ + 32, /* firmware */ 49, /* deco_info1 */ 50, /* deco_info1 */ 51, /* decomode */ @@ -156,7 +159,7 @@ static const hw_ostc_layout_t hw_ostc_layout_frog = { 19, /* temperature */ 34, /* battery volt after dive */ 23, /* desat */ - 32, /* fw_version */ + 32, /* firmware */ /* 32 or 34??? Anton says 32 (34 == battery), Jef says 34 */ 49, /* deco_info1 */ 50, /* deco_info2 */ 51, /* decomode */ @@ -173,7 +176,7 @@ static const hw_ostc_layout_t hw_ostc_layout_ostc3 = { 22, /* temperature */ 50, /* battery volt after dive */ 26, /* desat */ - 48, /* fw_version */ + 48, /* firmware */ 77, /* deco_info1 */ 78, /* deco_info2 */ 79, /* decomode */ @@ -217,7 +220,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) } // Check the profile version - unsigned int version = data[parser->frog ? 8 : 2]; + unsigned int version = data[parser->hwos ? 8 : 2]; const hw_ostc_layout_t *layout = NULL; unsigned int header = 0; switch (version) { @@ -303,7 +306,7 @@ hw_ostc_parser_cache (hw_ostc_parser_t *parser) } dc_status_t -hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int frog) +hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int hwos, unsigned int model) { hw_ostc_parser_t *parser = NULL; @@ -318,7 +321,8 @@ hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int se } // Set the default values. - parser->frog = frog; + parser->hwos = hwos; + parser->model = model; parser->cached = 0; parser->version = 0; parser->header = 0; @@ -338,6 +342,18 @@ hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int se } +dc_status_t +hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int hwos) +{ + return hw_ostc_parser_create_internal (out, context, serial, hwos, 0); +} + +dc_status_t +hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int model) +{ + return hw_ostc_parser_create_internal (out, context, serial, 1, model); +} + static dc_status_t hw_ostc_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size) { @@ -551,9 +567,9 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned snprintf(buf, BUFLEN, "%0u:%02u", array_uint16_le (data + layout->desat) / 60, array_uint16_le (data + layout->desat) % 60); break; - case 2: /* fw_version */ + case 2: /* firmware */ string->desc = "FW Version"; - snprintf(buf, BUFLEN, "%0u.%02u", data[layout->fw_version], data[layout->fw_version + 1]); + snprintf(buf, BUFLEN, "%0u.%02u", data[layout->firmware], data[layout->firmware + 1]); break; case 3: /* serial */ string->desc = "Serial"; @@ -681,6 +697,14 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call } } + // Get the firmware version. + unsigned int firmware = 0; + if (parser->model == OSTC4) { + firmware = array_uint16_le (data + layout->firmware); + } else { + firmware = array_uint16_be (data + layout->firmware); + } + unsigned int time = 0; unsigned int nsamples = 0; @@ -901,6 +925,10 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata); break; case 1: // Deco / NDL + // Due to a firmware bug, the deco/ndl info is incorrect for + // all OSTC4 dives with a firmware older than version 1.0.8. + if (parser->model == OSTC4 && firmware < 0x0810) + break; if (data[offset]) { sample.deco.type = DC_DECO_DECOSTOP; sample.deco.depth = data[offset]; diff --git a/src/irda.c b/src/irda.c index 57b5076..00b749c 100644 --- a/src/irda.c +++ b/src/irda.c @@ -39,18 +39,31 @@ #endif #include "irda.h" +#include "common-private.h" #include "context-private.h" #include "array.h" #ifdef _WIN32 +typedef int s_ssize_t; +typedef DWORD s_errcode_t; #define S_ERRNO WSAGetLastError () #define S_EAGAIN WSAEWOULDBLOCK +#define S_ENOMEM WSA_NOT_ENOUGH_MEMORY +#define S_EINVAL WSAEINVAL +#define S_EACCES WSAEACCES +#define S_EAFNOSUPPORT WSAEAFNOSUPPORT #define S_INVALID INVALID_SOCKET #define S_IOCTL ioctlsocket #define S_CLOSE closesocket #else +typedef ssize_t s_ssize_t; +typedef int s_errcode_t; #define S_ERRNO errno #define S_EAGAIN EAGAIN +#define S_ENOMEM ENOMEM +#define S_EINVAL EINVAL +#define S_EACCES EACCES +#define S_EAFNOSUPPORT EAFNOSUPPORT #define S_INVALID -1 #define S_IOCTL ioctl #define S_CLOSE close @@ -60,32 +73,47 @@ #define snprintf _snprintf #endif -struct irda_t { +struct dc_irda_t { dc_context_t *context; #ifdef _WIN32 SOCKET fd; #else int fd; #endif - long timeout; + int timeout; }; - -int -irda_socket_open (irda_t **out, dc_context_t *context) +static dc_status_t +syserror(s_errcode_t errcode) { + switch (errcode) { + case S_EINVAL: + return DC_STATUS_INVALIDARGS; + case S_ENOMEM: + return DC_STATUS_NOMEMORY; + case S_EACCES: + return DC_STATUS_NOACCESS; + case S_EAFNOSUPPORT: + return DC_STATUS_UNSUPPORTED; + default: + return DC_STATUS_IO; + } +} + +dc_status_t +dc_irda_open (dc_irda_t **out, dc_context_t *context) +{ + dc_status_t status = DC_STATUS_SUCCESS; + dc_irda_t *device = NULL; + if (out == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; // Allocate memory. - irda_t *device = (irda_t *) malloc (sizeof (irda_t)); + device = (dc_irda_t *) malloc (sizeof (dc_irda_t)); if (device == NULL) { -#ifdef _WIN32 - SYSERROR (context, ERROR_OUTOFMEMORY); -#else - SYSERROR (context, ENOMEM); -#endif - return -1; // ENOMEM (Not enough space) + SYSERROR (context, S_ENOMEM); + return DC_STATUS_NOMEMORY; } // Library context. @@ -101,6 +129,7 @@ irda_socket_open (irda_t **out, dc_context_t *context) int rc = WSAStartup (wVersionRequested, &wsaData); if (rc != 0) { SYSERROR (context, rc); + status = DC_STATUS_UNSUPPORTED; goto error_free; } @@ -110,6 +139,7 @@ irda_socket_open (irda_t **out, dc_context_t *context) if (LOBYTE (wsaData.wVersion) != 2 || HIBYTE (wsaData.wVersion) != 2) { ERROR (context, "Incorrect winsock version."); + status = DC_STATUS_UNSUPPORTED; goto error_wsacleanup; } #endif @@ -117,13 +147,15 @@ irda_socket_open (irda_t **out, dc_context_t *context) // Open the socket. device->fd = socket (AF_IRDA, SOCK_STREAM, 0); if (device->fd == S_INVALID) { - SYSERROR (context, S_ERRNO); + s_errcode_t errcode = S_ERRNO; + SYSERROR (context, errcode); + status = syserror(errcode); goto error_wsacleanup; } *out = device; - return 0; + return DC_STATUS_SUCCESS; error_wsacleanup: #ifdef _WIN32 @@ -131,53 +163,53 @@ error_wsacleanup: error_free: #endif free (device); - return -1; + return status; } - -int -irda_socket_close (irda_t *device) +dc_status_t +dc_irda_close (dc_irda_t *device) { - int errcode = 0; + dc_status_t status = DC_STATUS_SUCCESS; if (device == NULL) - return -1; + return DC_STATUS_SUCCESS; // Terminate all send and receive operations. shutdown (device->fd, 0); // Close the socket. if (S_CLOSE (device->fd) != 0) { - SYSERROR (device->context, S_ERRNO); - errcode = -1; + s_errcode_t errcode = S_ERRNO; + SYSERROR (device->context, errcode); + dc_status_set_error(&status, syserror(errcode)); } #ifdef _WIN32 // Terminate the winsock dll. if (WSACleanup () != 0) { - SYSERROR (device->context, S_ERRNO); - errcode = -1; + s_errcode_t errcode = S_ERRNO; + SYSERROR (device->context, errcode); + dc_status_set_error(&status, syserror(errcode)); } #endif // Free memory. free (device); - return errcode; + return status; } - -int -irda_socket_set_timeout (irda_t *device, long timeout) +dc_status_t +dc_irda_set_timeout (dc_irda_t *device, int timeout) { if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; - INFO (device->context, "Timeout: value=%li", timeout); + INFO (device->context, "Timeout: value=%i", timeout); device->timeout = timeout; - return 0; + return DC_STATUS_SUCCESS; } @@ -192,11 +224,11 @@ irda_socket_set_timeout (irda_t *device, long timeout) sizeof (struct irda_device_info) * (DISCOVER_MAX_DEVICES - 1) #endif -int -irda_socket_discover (irda_t *device, irda_callback_t callback, void *userdata) +dc_status_t +dc_irda_discover (dc_irda_t *device, dc_irda_callback_t callback, void *userdata) { if (device == NULL) - return -1; + return DC_STATUS_INVALIDARGS; unsigned char data[DISCOVER_BUFSIZE] = {0}; #ifdef _WIN32 @@ -221,15 +253,16 @@ irda_socket_discover (irda_t *device, irda_callback_t callback, void *userdata) // discovered, while on Windows it succeeds and sets the number // of devices to zero. Both situations are handled the same here. if (rc != 0) { - if (S_ERRNO != S_EAGAIN) { - SYSERROR (device->context, S_ERRNO); - return -1; // Error during getsockopt call. + s_errcode_t errcode = S_ERRNO; + if (errcode != S_EAGAIN) { + SYSERROR (device->context, errcode); + return syserror(errcode); } } // Abort if the maximum number of retries is reached. if (nretries++ >= DISCOVER_MAX_RETRIES) - return 0; + return DC_STATUS_SUCCESS; // Restore the size parameter in case it was // modified by the previous getsockopt call. @@ -266,15 +299,14 @@ irda_socket_discover (irda_t *device, irda_callback_t callback, void *userdata) } } - return 0; + return DC_STATUS_SUCCESS; } - -int -irda_socket_connect_name (irda_t *device, unsigned int address, const char *name) +dc_status_t +dc_irda_connect_name (dc_irda_t *device, unsigned int address, const char *name) { if (device == NULL) - return -1; + return DC_STATUS_INVALIDARGS; INFO (device->context, "Connect: address=%08x, name=%s", address, name ? name : ""); @@ -300,18 +332,19 @@ irda_socket_connect_name (irda_t *device, unsigned int address, const char *name #endif if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) { - SYSERROR (device->context, S_ERRNO); - return -1; + s_errcode_t errcode = S_ERRNO; + SYSERROR (device->context, errcode); + return syserror(errcode); } - return 0; + return DC_STATUS_SUCCESS; } -int -irda_socket_connect_lsap (irda_t *device, unsigned int address, unsigned int lsap) +dc_status_t +dc_irda_connect_lsap (dc_irda_t *device, unsigned int address, unsigned int lsap) { if (device == NULL) - return -1; + return DC_STATUS_INVALIDARGS; INFO (device->context, "Connect: address=%08x, lsap=%u", address, lsap); @@ -332,19 +365,19 @@ irda_socket_connect_lsap (irda_t *device, unsigned int address, unsigned int lsa #endif if (connect (device->fd, (struct sockaddr *) &peer, sizeof (peer)) != 0) { - SYSERROR (device->context, S_ERRNO); - return -1; + s_errcode_t errcode = S_ERRNO; + SYSERROR (device->context, errcode); + return syserror(errcode); } - return 0; + return DC_STATUS_SUCCESS; } - -int -irda_socket_available (irda_t *device) +dc_status_t +dc_irda_get_available (dc_irda_t *device, size_t *value) { if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; #ifdef _WIN32 unsigned long bytes = 0; @@ -353,19 +386,27 @@ irda_socket_available (irda_t *device) #endif if (S_IOCTL (device->fd, FIONREAD, &bytes) != 0) { - SYSERROR (device->context, S_ERRNO); - return -1; + s_errcode_t errcode = S_ERRNO; + SYSERROR (device->context, errcode); + return syserror(errcode); } - return bytes; + if (value) + *value = bytes; + + return DC_STATUS_SUCCESS; } - -int -irda_socket_read (irda_t *device, void *data, unsigned int size) +dc_status_t +dc_irda_read (dc_irda_t *device, void *data, size_t size, size_t *actual) { - if (device == NULL) - return -1; // EINVAL (Invalid argument) + dc_status_t status = DC_STATUS_SUCCESS; + size_t nbytes = 0; + + if (device == NULL) { + status = DC_STATUS_INVALIDARGS; + goto out; + } struct timeval tv; if (device->timeout >= 0) { @@ -377,20 +418,23 @@ irda_socket_read (irda_t *device, void *data, unsigned int size) FD_ZERO (&fds); FD_SET (device->fd, &fds); - unsigned int nbytes = 0; while (nbytes < size) { int rc = select (device->fd + 1, &fds, NULL, NULL, (device->timeout >= 0 ? &tv : NULL)); if (rc < 0) { - SYSERROR (device->context, S_ERRNO); - return -1; // Error during select call. + s_errcode_t errcode = S_ERRNO; + SYSERROR (device->context, errcode); + status = syserror(errcode); + goto out; } else if (rc == 0) { break; // Timeout. } - int n = recv (device->fd, (char*) data + nbytes, size - nbytes, 0); + s_ssize_t n = recv (device->fd, (char*) data + nbytes, size - nbytes, 0); if (n < 0) { - SYSERROR (device->context, S_ERRNO); - return -1; // Error during recv call. + s_errcode_t errcode = S_ERRNO; + SYSERROR (device->context, errcode); + status = syserror(errcode); + goto out; } else if (n == 0) { break; // EOF reached. } @@ -398,30 +442,51 @@ irda_socket_read (irda_t *device, void *data, unsigned int size) nbytes += n; } + if (nbytes != size) { + status = DC_STATUS_TIMEOUT; + } + +out: HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes); - return nbytes; + if (actual) + *actual = nbytes; + + return status; } - -int -irda_socket_write (irda_t *device, const void *data, unsigned int size) +dc_status_t +dc_irda_write (dc_irda_t *device, const void *data, size_t size, size_t *actual) { - if (device == NULL) - return -1; // EINVAL (Invalid argument) + dc_status_t status = DC_STATUS_SUCCESS; + size_t nbytes = 0; + + if (device == NULL) { + status = DC_STATUS_INVALIDARGS; + goto out; + } - unsigned int nbytes = 0; while (nbytes < size) { - int n = send (device->fd, (char*) data + nbytes, size - nbytes, 0); + s_ssize_t n = send (device->fd, (char*) data + nbytes, size - nbytes, 0); if (n < 0) { - SYSERROR (device->context, S_ERRNO); - return -1; // Error during send call. + s_errcode_t errcode = S_ERRNO; + SYSERROR (device->context, errcode); + status = syserror(errcode); + goto out; } nbytes += n; } + if (nbytes != size) { + status = DC_STATUS_TIMEOUT; + } + +out: HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes); - return nbytes; + if (actual) + *actual = nbytes; + + return status; } diff --git a/src/irda.h b/src/irda.h index d83037a..84d2f4d 100644 --- a/src/irda.h +++ b/src/irda.h @@ -19,37 +19,161 @@ * MA 02110-1301 USA */ -#ifndef IRDA_H -#define IRDA_H +#ifndef DC_IRDA_H +#define DC_IRDA_H +#include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -typedef struct irda_t irda_t; +/** + * Opaque object representing an IrDA connection. + */ +typedef struct dc_irda_t dc_irda_t; -typedef void (*irda_callback_t) (unsigned int address, const char *name, unsigned int charset, unsigned int hints, void *userdata); +/** + * IrDA enumeration callback. + * + * @param[in] address The IrDA device address. + * @param[in] name The IrDA device name. + * @param[in] charset The IrDA device character set. + * @param[in] hints The IrDA device hints. + * @param[in] userdata The user data pointer. + */ +typedef void (*dc_irda_callback_t) (unsigned int address, const char *name, unsigned int charset, unsigned int hints, void *userdata); -int irda_socket_open (irda_t **device, dc_context_t *context); +/** + * Open an IrDA connection. + * + * @param[out] irda A location to store the IrDA connection. + * @param[in] context A valid context object. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_irda_open (dc_irda_t **irda, dc_context_t *context); -int irda_socket_close (irda_t *device); +/** + * Close the IrDA connection and free all resources. + * + * @param[in] irda A valid IrDA connection. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_irda_close (dc_irda_t *irda); -int irda_socket_set_timeout (irda_t *device, long timeout); +/** + * Set the read timeout. + * + * There are three distinct modes available: + * + * 1. Blocking (timeout < 0): + * + * The read operation is blocked until all the requested bytes have + * been received. If the requested number of bytes does not arrive, + * the operation will block forever. + * + * 2. Non-blocking (timeout == 0): + * + * The read operation returns immediately with the bytes that have + * already been received, even if no bytes have been received. + * + * 3. Timeout (timeout > 0): + * + * The read operation is blocked until all the requested bytes have + * been received. If the requested number of bytes does not arrive + * within the specified amount of time, the operation will return + * with the bytes that have already been received. + * + * @param[in] irda A valid IrDA connection. + * @param[in] timeout The timeout in milliseconds. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_irda_set_timeout (dc_irda_t *irda, int timeout); -int irda_socket_discover (irda_t *device, irda_callback_t callback, void *userdata); +/** + * Enumerate the IrDA devices. + * + * @param[in] irda A valid IrDA connection. + * @param[in] callback The callback function to call. + * @param[in] userdata User data to pass to the callback function. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_irda_discover (dc_irda_t *irda, dc_irda_callback_t callback, void *userdata); -int irda_socket_connect_name (irda_t *device, unsigned int address, const char *name); -int irda_socket_connect_lsap (irda_t *device, unsigned int address, unsigned int lsap); +/** + * Connect to an IrDA device. + * + * @param[in] irda A valid IrDA connection. + * @param[in] address The IrDA device address. + * @param[in] name The IrDA service name. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_irda_connect_name (dc_irda_t *irda, unsigned int address, const char *name); -int irda_socket_available (irda_t *device); +/** + * Connect to an IrDA device. + * + * @param[in] irda A valid IrDA connection. + * @param[in] address The IrDA device address. + * @param[in] lsap The IrDA LSAP number. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_irda_connect_lsap (dc_irda_t *irda, unsigned int address, unsigned int lsap); -int irda_socket_read (irda_t *device, void *data, unsigned int size); +/** + * Query the number of available bytes in the input buffer. + * + * @param[in] irda A valid IrDA connection. + * @param[out] value A location to store the number of bytes in the + * input buffer. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_irda_get_available (dc_irda_t *irda, size_t *value); -int irda_socket_write (irda_t *device, const void *data, unsigned int size); +/** + * Read data from the IrDA connection. + * + * @param[in] irda A valid IrDA connection. + * @param[out] data The memory buffer to read the data into. + * @param[in] size The number of bytes to read. + * @param[out] actual An (optional) location to store the actual + * number of bytes transferred. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_irda_read (dc_irda_t *irda, void *data, size_t size, size_t *actual); + +/** + * Write data to the IrDA connection. + * + * @param[in] irda A valid IrDA connection. + * @param[in] data The memory buffer to write the data from. + * @param[in] size The number of bytes to write. + * @param[out] actual An (optional) location to store the actual + * number of bytes transferred. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_irda_write (dc_irda_t *irda, const void *data, size_t size, size_t *actual); #ifdef __cplusplus } #endif /* __cplusplus */ -#endif /* IRDA_H */ +#endif /* DC_IRDA_H */ diff --git a/src/irda_dummy.c b/src/irda_dummy.c index 504aee8..7579324 100644 --- a/src/irda_dummy.c +++ b/src/irda_dummy.c @@ -23,65 +23,56 @@ #include "irda.h" - -int -irda_socket_open (irda_t **out, dc_context_t *context) +dc_status_t +dc_irda_open (dc_irda_t **out, dc_context_t *context) { - return -1; + return DC_STATUS_UNSUPPORTED; } - -int -irda_socket_close (irda_t *device) +dc_status_t +dc_irda_close (dc_irda_t *device) { - return -1; + return DC_STATUS_UNSUPPORTED; } - -int -irda_socket_set_timeout (irda_t *device, long timeout) +dc_status_t +dc_irda_set_timeout (dc_irda_t *device, int timeout) { - return -1; + return DC_STATUS_UNSUPPORTED; } - -int -irda_socket_discover (irda_t *device, irda_callback_t callback, void *userdata) +dc_status_t +dc_irda_discover (dc_irda_t *device, dc_irda_callback_t callback, void *userdata) { - return -1; + return DC_STATUS_UNSUPPORTED; } - -int -irda_socket_connect_name (irda_t *device, unsigned int address, const char *name) +dc_status_t +dc_irda_connect_name (dc_irda_t *device, unsigned int address, const char *name) { - return -1; + return DC_STATUS_UNSUPPORTED; } - -int -irda_socket_connect_lsap (irda_t *device, unsigned int address, unsigned int lsap) +dc_status_t +dc_irda_connect_lsap (dc_irda_t *device, unsigned int address, unsigned int lsap) { - return -1; + return DC_STATUS_UNSUPPORTED; } - -int -irda_socket_available (irda_t *device) +dc_status_t +dc_irda_get_available (dc_irda_t *device, size_t *value) { - return -1; + return DC_STATUS_UNSUPPORTED; } - -int -irda_socket_read (irda_t *device, void *data, unsigned int size) +dc_status_t +dc_irda_read (dc_irda_t *device, void *data, size_t size, size_t *actual) { - return -1; + return DC_STATUS_UNSUPPORTED; } - -int -irda_socket_write (irda_t *device, const void *data, unsigned int size) +dc_status_t +dc_irda_write (dc_irda_t *device, const void *data, size_t size, size_t *actual) { - return -1; + return DC_STATUS_UNSUPPORTED; } diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index c81fe07..5fe3442 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -34,6 +34,7 @@ dc_descriptor_get_model dc_descriptor_get_transport dc_parser_new +dc_parser_new2 dc_parser_get_type dc_parser_set_data dc_parser_get_datetime @@ -58,9 +59,11 @@ mares_nemo_parser_create mares_darwin_parser_create mares_iconhd_parser_create oceanic_vtpro_parser_create +oceanic_vtpro_parser_create2 oceanic_veo250_parser_create oceanic_atom2_parser_create hw_ostc_parser_create +hw_ostc3_parser_create cressi_edy_parser_create cressi_leonardo_parser_create atomics_cobalt_parser_create @@ -105,6 +108,7 @@ oceanic_veo250_device_open oceanic_veo250_device_version oceanic_veo250_device_keepalive oceanic_vtpro_device_open +oceanic_vtpro_device_open2 oceanic_vtpro_device_version oceanic_vtpro_device_keepalive reefnet_sensus_device_open diff --git a/src/mares_common.c b/src/mares_common.c index 6f0c3dd..b157dc2 100644 --- a/src/mares_common.c +++ b/src/mares_common.c @@ -28,11 +28,6 @@ #include "checksum.h" #include "array.h" -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define MAXRETRIES 4 #define FP_OFFSET 8 @@ -86,29 +81,30 @@ mares_common_make_ascii (const unsigned char raw[], unsigned int rsize, unsigned static dc_status_t mares_common_packet (mares_common_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; if (device->delay) { - serial_sleep (device->port, device->delay); + dc_serial_sleep (device->port, device->delay); } // Send the command to the device. - int n = serial_write (device->port, command, csize); - if (n != csize) { + status = dc_serial_write (device->port, command, csize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } if (device->echo) { // Receive the echo of the command. unsigned char echo[PACKETSIZE] = {0}; - n = serial_read (device->port, echo, csize); - if (n != csize) { + status = dc_serial_read (device->port, echo, csize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the echo."); - return EXITCODE (n); + return status; } // Verify the echo. @@ -118,10 +114,10 @@ mares_common_packet (mares_common_device_t *device, const unsigned char command[ } // Receive the answer of the device. - n = serial_read (device->port, answer, asize); - if (n != asize) { + status = dc_serial_read (device->port, answer, asize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the header and trailer of the packet. @@ -159,8 +155,8 @@ mares_common_transfer (mares_common_device_t *device, const unsigned char comman return rc; // Discard any garbage bytes. - serial_sleep (device->port, 100); - serial_flush (device->port, SERIAL_QUEUE_INPUT); + dc_serial_sleep (device->port, 100); + dc_serial_purge (device->port, DC_DIRECTION_INPUT); } return rc; diff --git a/src/mares_common.h b/src/mares_common.h index 33228c5..4652d06 100644 --- a/src/mares_common.h +++ b/src/mares_common.h @@ -41,7 +41,7 @@ typedef struct mares_common_layout_t { typedef struct mares_common_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; unsigned int echo; unsigned int delay; } mares_common_device_t; diff --git a/src/mares_darwin.c b/src/mares_darwin.c index f8a39d9..3f06a4a 100644 --- a/src/mares_darwin.c +++ b/src/mares_darwin.c @@ -122,39 +122,43 @@ mares_darwin_device_open (dc_device_t **out, dc_context_t *context, const char * device->layout = &mares_darwin_layout; // Open the device. - int rc = serial_open (&device->base.port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->base.port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (9600 8N1). - rc = serial_configure (device->base.port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->base.port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (1000 ms). - if (serial_set_timeout (device->base.port, 1000) == -1) { + status = dc_serial_set_timeout (device->base.port, 1000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } - // Set the DTR/RTS lines. - if (serial_set_dtr (device->base.port, 1) == -1 || - serial_set_rts (device->base.port, 1) == -1) { - ERROR (context, "Failed to set the DTR/RTS line."); - status = DC_STATUS_IO; + // Set the DTR line. + status = dc_serial_set_dtr (device->base.port, 1); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to set the DTR line."); + goto error_close; + } + + // Set the RTS line. + status = dc_serial_set_rts (device->base.port, 1); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to set the RTS line."); goto error_close; } // Make sure everything is in a sane state. - serial_sleep (device->base.port, 100); - serial_flush (device->base.port, SERIAL_QUEUE_BOTH); + dc_serial_sleep (device->base.port, 100); + dc_serial_purge (device->base.port, DC_DIRECTION_ALL); // Override the base class values. device->base.echo = 1; @@ -165,7 +169,7 @@ mares_darwin_device_open (dc_device_t **out, dc_context_t *context, const char * return DC_STATUS_SUCCESS; error_close: - serial_close (device->base.port); + dc_serial_close (device->base.port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -176,10 +180,12 @@ mares_darwin_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; mares_darwin_device_t *device = (mares_darwin_device_t *) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->base.port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->base.port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; diff --git a/src/mares_iconhd.c b/src/mares_iconhd.c index 79dda55..9c33307 100644 --- a/src/mares_iconhd.c +++ b/src/mares_iconhd.c @@ -34,11 +34,6 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &mares_iconhd_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define MATRIX 0x0F #define SMART 0x000010 #define SMARTAPNEA 0x010010 @@ -69,7 +64,7 @@ typedef struct mares_iconhd_model_t { typedef struct mares_iconhd_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; const mares_iconhd_layout_t *layout; unsigned char fingerprint[10]; unsigned char version[140]; @@ -150,6 +145,7 @@ mares_iconhd_transfer (mares_iconhd_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; assert (csize >= 2); @@ -158,18 +154,18 @@ mares_iconhd_transfer (mares_iconhd_device_t *device, return DC_STATUS_CANCELLED; // Send the command header to the dive computer. - int n = serial_write (device->port, command, 2); - if (n != 2) { + status = dc_serial_write (device->port, command, 2, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Receive the header byte. unsigned char header[1] = {0}; - n = serial_read (device->port, header, sizeof (header)); - if (n != sizeof (header)) { + status = dc_serial_read (device->port, header, sizeof (header), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the header byte. @@ -180,26 +176,26 @@ mares_iconhd_transfer (mares_iconhd_device_t *device, // Send the command payload to the dive computer. if (csize > 2) { - n = serial_write (device->port, command + 2, csize - 2); - if (n != csize - 2) { + status = dc_serial_write (device->port, command + 2, csize - 2, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } } // Read the packet. - n = serial_read (device->port, answer, asize); - if (n != asize) { + status = dc_serial_read (device->port, answer, asize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Receive the trailer byte. unsigned char trailer[1] = {0}; - n = serial_read (device->port, trailer, sizeof (trailer)); - if (n != sizeof (trailer)) { + status = dc_serial_read (device->port, trailer, sizeof (trailer), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the trailer byte. @@ -237,39 +233,42 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char * device->packetsize = 0; // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (115200 8E1). - rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_EVEN, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_EVEN, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (1000 ms). - if (serial_set_timeout (device->port, 1000) == -1) { + status = dc_serial_set_timeout (device->port, 1000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } - // Set the DTR/RTS lines. - if (serial_set_dtr (device->port, 0) == -1 || - serial_set_rts (device->port, 0) == -1) - { - ERROR (context, "Failed to set the DTR/RTS line."); - status = DC_STATUS_IO; + // Clear the DTR line. + status = dc_serial_set_dtr (device->port, 0); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to clear the DTR line."); + goto error_close; + } + + // Clear the RTS line. + status = dc_serial_set_rts (device->port, 0); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to clear the RTS line."); goto error_close; } // Make sure everything is in a sane state. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); // Send the version command. unsigned char command[] = {0xC2, 0x67}; @@ -312,7 +311,7 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, const char * return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -324,10 +323,12 @@ mares_iconhd_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; mares_iconhd_device_t *device = (mares_iconhd_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; diff --git a/src/mares_nemo.c b/src/mares_nemo.c index 7f71dbf..16824ae 100644 --- a/src/mares_nemo.c +++ b/src/mares_nemo.c @@ -33,11 +33,6 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &mares_nemo_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #ifdef PACKETSIZE #undef PACKETSIZE /* Override the common value. */ #endif @@ -51,7 +46,7 @@ typedef struct mares_nemo_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; unsigned char fingerprint[5]; } mares_nemo_device_t; @@ -109,45 +104,49 @@ mares_nemo_device_open (dc_device_t **out, dc_context_t *context, const char *na memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (9600 8N1). - rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (1000 ms). - if (serial_set_timeout (device->port, 1000) == -1) { + status = dc_serial_set_timeout (device->port, 1000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } - // Set the DTR/RTS lines. - if (serial_set_dtr (device->port, 1) == -1 || - serial_set_rts (device->port, 1) == -1) { - ERROR (context, "Failed to set the DTR/RTS line."); - status = DC_STATUS_IO; + // Set the DTR line. + status = dc_serial_set_dtr (device->port, 1); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to set the DTR line."); + goto error_close; + } + + // Set the RTS line. + status = dc_serial_set_rts (device->port, 1); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to set the RTS line."); goto error_close; } // Make sure everything is in a sane state. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -159,10 +158,12 @@ mares_nemo_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; mares_nemo_device_t *device = (mares_nemo_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -189,6 +190,7 @@ mares_nemo_device_set_fingerprint (dc_device_t *abstract, const unsigned char da static dc_status_t mares_nemo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) { + dc_status_t status = DC_STATUS_SUCCESS; mares_nemo_device_t *device = (mares_nemo_device_t *) abstract; // Erase the current contents of the buffer and @@ -204,21 +206,22 @@ mares_nemo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); // Wait until some data arrives. - while (serial_get_received (device->port) == 0) { + size_t available = 0; + while (dc_serial_get_available (device->port, &available) == DC_STATUS_SUCCESS && available == 0) { if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; device_event_emit (abstract, DC_EVENT_WAITING, NULL); - serial_sleep (device->port, 100); + dc_serial_sleep (device->port, 100); } // Receive the header of the package. unsigned char header = 0x00; for (unsigned int i = 0; i < 20;) { - int n = serial_read (device->port, &header, 1); - if (n != 1) { + status = dc_serial_read (device->port, &header, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the header."); - return EXITCODE (n); + return status; } if (header == 0xEE) { i++; // Continue. @@ -235,10 +238,10 @@ mares_nemo_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) while (nbytes < MEMORYSIZE) { // Read the packet. unsigned char packet[(PACKETSIZE + 1) * 2] = {0}; - int n = serial_read (device->port, packet, sizeof (packet)); - if (n != sizeof (packet)) { + status = dc_serial_read (device->port, packet, sizeof (packet), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the checksums of the packet. diff --git a/src/mares_puck.c b/src/mares_puck.c index 67666df..853ad03 100644 --- a/src/mares_puck.c +++ b/src/mares_puck.c @@ -110,38 +110,42 @@ mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *na memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - int rc = serial_open (&device->base.port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->base.port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (38400 8N1). - rc = serial_configure (device->base.port, 38400, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->base.port, 38400, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (1000 ms). - if (serial_set_timeout (device->base.port, 1000) == -1) { + status = dc_serial_set_timeout (device->base.port, 1000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } - // Clear the DTR/RTS lines. - if (serial_set_dtr (device->base.port, 0) == -1 || - serial_set_rts (device->base.port, 0) == -1) { - ERROR (context, "Failed to set the DTR/RTS line."); - status = DC_STATUS_IO; + // Clear the DTR line. + status = dc_serial_set_dtr (device->base.port, 0); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to clear the DTR line."); + goto error_close; + } + + // Clear the RTS line. + status = dc_serial_set_rts (device->base.port, 0); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to clear the RTS line."); goto error_close; } // Make sure everything is in a sane state. - serial_flush (device->base.port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->base.port, DC_DIRECTION_ALL); // Identify the model number. unsigned char header[PACKETSIZE] = {0}; @@ -172,7 +176,7 @@ mares_puck_device_open (dc_device_t **out, dc_context_t *context, const char *na return DC_STATUS_SUCCESS; error_close: - serial_close (device->base.port); + dc_serial_close (device->base.port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -184,10 +188,12 @@ mares_puck_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; mares_puck_device_t *device = (mares_puck_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->base.port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->base.port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index 9904131..89741bc 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -32,7 +32,7 @@ #include "ringbuffer.h" #include "checksum.h" -#define ISINSTANCE(device) dc_device_isinstance((device), &oceanic_atom2_device_vtable) +#define ISINSTANCE(device) dc_device_isinstance((device), &oceanic_atom2_device_vtable.base) #define VTX 0x4557 @@ -40,11 +40,6 @@ #define MAXDELAY 16 #define INVALID 0xFFFFFFFF -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define CMD_INIT 0xA8 #define CMD_VERSION 0x84 #define CMD_READ1 0xB1 @@ -59,7 +54,7 @@ typedef struct oceanic_atom2_device_t { oceanic_common_device_t base; - serial_t *port; + dc_serial_t *port; unsigned int delay; unsigned int bigpage; unsigned char cache[256]; @@ -70,15 +65,19 @@ static dc_status_t oceanic_atom2_device_read (dc_device_t *abstract, unsigned in static dc_status_t oceanic_atom2_device_write (dc_device_t *abstract, unsigned int address, const unsigned char data[], unsigned int size); static dc_status_t oceanic_atom2_device_close (dc_device_t *abstract); -static const dc_device_vtable_t oceanic_atom2_device_vtable = { - sizeof(oceanic_atom2_device_t), - DC_FAMILY_OCEANIC_ATOM2, - oceanic_common_device_set_fingerprint, /* set_fingerprint */ - oceanic_atom2_device_read, /* read */ - oceanic_atom2_device_write, /* write */ - oceanic_common_device_dump, /* dump */ - oceanic_common_device_foreach, /* foreach */ - oceanic_atom2_device_close /* close */ +static const oceanic_common_device_vtable_t oceanic_atom2_device_vtable = { + { + sizeof(oceanic_atom2_device_t), + DC_FAMILY_OCEANIC_ATOM2, + oceanic_common_device_set_fingerprint, /* set_fingerprint */ + oceanic_atom2_device_read, /* read */ + oceanic_atom2_device_write, /* write */ + oceanic_common_device_dump, /* dump */ + oceanic_common_device_foreach, /* foreach */ + oceanic_atom2_device_close /* close */ + }, + oceanic_common_device_logbook, + oceanic_common_device_profile, }; static const oceanic_common_version_t aeris_f10_version[] = { @@ -114,6 +113,7 @@ static const oceanic_common_version_t oceanic_atom2b_version[] = { {"ELEMENT2 \0\0 512K"}, {"OCEVEO20 \0\0 512K"}, {"TUSAZEN \0\0 512K"}, + {"AQUAI300 \0\0 512K"}, }; static const oceanic_common_version_t oceanic_atom2c_version[] = { @@ -147,6 +147,7 @@ static const oceanic_common_version_t oceanic_oc1_version[] = { {"OCWATCH R\0\0 1024"}, {"OC1WATCH \0\0 1024"}, {"OCSWATCH \0\0 1024"}, + {"AQUAI550 \0\0 1024"}, }; static const oceanic_common_version_t oceanic_oci_version[] = { @@ -162,6 +163,7 @@ static const oceanic_common_version_t oceanic_vt4_version[] = { {"OCEANVT4 \0\0 1024"}, {"OCEAVT41 \0\0 1024"}, {"AERISAIR \0\0 1024"}, + {"SWVISION \0\0 1024"}, }; static const oceanic_common_version_t hollis_tx1_version[] = { @@ -196,7 +198,8 @@ static const oceanic_common_layout_t aeris_f10_layout = { 0x0D80, /* rb_profile_begin */ 0x10000, /* rb_profile_end */ 0, /* pt_mode_global */ - 2 /* pt_mode_logbook */ + 2, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t aeris_f11_layout = { @@ -209,7 +212,8 @@ static const oceanic_common_layout_t aeris_f11_layout = { 0x0D80, /* rb_profile_begin */ 0x20000, /* rb_profile_end */ 0, /* pt_mode_global */ - 3 /* pt_mode_logbook */ + 3, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t oceanic_default_layout = { @@ -222,7 +226,8 @@ static const oceanic_common_layout_t oceanic_default_layout = { 0x0A40, /* rb_profile_begin */ 0x10000, /* rb_profile_end */ 0, /* pt_mode_global */ - 0 /* pt_mode_logbook */ + 0, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t oceanic_atom1_layout = { @@ -235,7 +240,8 @@ static const oceanic_common_layout_t oceanic_atom1_layout = { 0x0440, /* rb_profile_begin */ 0x8000, /* rb_profile_end */ 0, /* pt_mode_global */ - 0 /* pt_mode_logbook */ + 0, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t oceanic_atom2a_layout = { @@ -248,7 +254,8 @@ static const oceanic_common_layout_t oceanic_atom2a_layout = { 0x0A40, /* rb_profile_begin */ 0xFE00, /* rb_profile_end */ 0, /* pt_mode_global */ - 0 /* pt_mode_logbook */ + 0, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t oceanic_atom2b_layout = { @@ -261,7 +268,8 @@ static const oceanic_common_layout_t oceanic_atom2b_layout = { 0x0A40, /* rb_profile_begin */ 0xFE00, /* rb_profile_end */ 0, /* pt_mode_global */ - 0 /* pt_mode_logbook */ + 0, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t oceanic_atom2c_layout = { @@ -274,7 +282,8 @@ static const oceanic_common_layout_t oceanic_atom2c_layout = { 0x0A40, /* rb_profile_begin */ 0xFFF0, /* rb_profile_end */ 0, /* pt_mode_global */ - 0 /* pt_mode_logbook */ + 0, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t oceanic_proplus3_layout = { @@ -287,7 +296,8 @@ static const oceanic_common_layout_t oceanic_proplus3_layout = { 0x0A40, /* rb_profile_begin */ 0xFE00, /* rb_profile_end */ 0, /* pt_mode_global */ - 0 /* pt_mode_logbook */ + 0, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t tusa_zenair_layout = { @@ -300,7 +310,8 @@ static const oceanic_common_layout_t tusa_zenair_layout = { 0x0A40, /* rb_profile_begin */ 0xFE00, /* rb_profile_end */ 0, /* pt_mode_global */ - 1 /* pt_mode_logbook */ + 1, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t oceanic_oc1_layout = { @@ -313,7 +324,8 @@ static const oceanic_common_layout_t oceanic_oc1_layout = { 0x0A40, /* rb_profile_begin */ 0x1FE00, /* rb_profile_end */ 0, /* pt_mode_global */ - 1 /* pt_mode_logbook */ + 1, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t oceanic_oci_layout = { @@ -326,7 +338,8 @@ static const oceanic_common_layout_t oceanic_oci_layout = { 0x1400, /* rb_profile_begin */ 0x1FE00, /* rb_profile_end */ 0, /* pt_mode_global */ - 1 /* pt_mode_logbook */ + 1, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t oceanic_atom3_layout = { @@ -339,7 +352,8 @@ static const oceanic_common_layout_t oceanic_atom3_layout = { 0x0A40, /* rb_profile_begin */ 0x1FE00, /* rb_profile_end */ 0, /* pt_mode_global */ - 1 /* pt_mode_logbook */ + 1, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t oceanic_vt4_layout = { @@ -352,7 +366,8 @@ static const oceanic_common_layout_t oceanic_vt4_layout = { 0x0A40, /* rb_profile_begin */ 0x1FE00, /* rb_profile_end */ 0, /* pt_mode_global */ - 1 /* pt_mode_logbook */ + 1, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t hollis_tx1_layout = { @@ -365,7 +380,8 @@ static const oceanic_common_layout_t hollis_tx1_layout = { 0x1000, /* rb_profile_begin */ 0x40000, /* rb_profile_end */ 0, /* pt_mode_global */ - 1 /* pt_mode_logbook */ + 1, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t oceanic_veo1_layout = { @@ -378,7 +394,8 @@ static const oceanic_common_layout_t oceanic_veo1_layout = { 0x0400, /* rb_profile_begin */ 0x0400, /* rb_profile_end */ 0, /* pt_mode_global */ - 0 /* pt_mode_logbook */ + 0, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t oceanic_reactpro_layout = { @@ -391,7 +408,8 @@ static const oceanic_common_layout_t oceanic_reactpro_layout = { 0x0600, /* rb_profile_begin */ 0xFFF0, /* rb_profile_end */ 1, /* pt_mode_global */ - 1 /* pt_mode_logbook */ + 1, /* pt_mode_logbook */ + 1, /* pt_mode_serial */ }; static const oceanic_common_layout_t aeris_a300cs_layout = { @@ -404,7 +422,8 @@ static const oceanic_common_layout_t aeris_a300cs_layout = { 0x1000, /* rb_profile_begin */ 0x3FE00, /* rb_profile_end */ 0, /* pt_mode_global */ - 1 /* pt_mode_logbook */ + 1, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t aqualung_i450t_layout = { @@ -417,26 +436,28 @@ static const oceanic_common_layout_t aqualung_i450t_layout = { 0x1400, /* rb_profile_begin */ 0x3FE00, /* rb_profile_end */ 0, /* pt_mode_global */ - 1 /* pt_mode_logbook */ + 1, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static dc_status_t oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int crc_size) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; if (device->delay) { - serial_sleep (device->port, device->delay); + dc_serial_sleep (device->port, device->delay); } // Send the command to the dive computer. - int n = serial_write (device->port, command, csize); - if (n != csize) { + status = dc_serial_write (device->port, command, csize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Get the correct ACK byte. @@ -447,10 +468,10 @@ oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char comman // Receive the response (ACK/NAK) of the dive computer. unsigned char response = 0; - n = serial_read (device->port, &response, 1); - if (n != 1) { + status = dc_serial_read (device->port, &response, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the response of the dive computer. @@ -461,10 +482,10 @@ oceanic_atom2_packet (oceanic_atom2_device_t *device, const unsigned char comman if (asize) { // Receive the answer of the dive computer. - int n = serial_read (device->port, answer, asize); - if (n != asize) { + status = dc_serial_read (device->port, answer, asize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the checksum of the answer. @@ -510,8 +531,8 @@ oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char comm device->delay++; // Delay the next attempt. - serial_sleep (device->port, 100); - serial_flush (device->port, SERIAL_QUEUE_INPUT); + dc_serial_sleep (device->port, 100); + dc_serial_purge (device->port, DC_DIRECTION_INPUT); } return DC_STATUS_SUCCESS; @@ -548,7 +569,7 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (oceanic_atom2_device_t *) dc_device_allocate (context, &oceanic_atom2_device_vtable); + device = (oceanic_atom2_device_t *) dc_device_allocate (context, &oceanic_atom2_device_vtable.base); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -565,10 +586,9 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char memset(device->cache, 0, sizeof(device->cache)); // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } @@ -579,29 +599,28 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char } // Set the serial communication protocol (38400 8N1). - rc = serial_configure (device->port, baudrate, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, baudrate, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (1000 ms). - if (serial_set_timeout (device->port, 1000) == -1) { + status = dc_serial_set_timeout (device->port, 1000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Give the interface 100 ms to settle and draw power up. - serial_sleep (device->port, 100); + dc_serial_sleep (device->port, 100); // Set the DTR/RTS lines. - serial_set_dtr(device->port, 1); - serial_set_rts(device->port, 1); + dc_serial_set_dtr(device->port, 1); + dc_serial_set_rts(device->port, 1); // Make sure everything is in a sane state. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); // Switch the device from surface mode into download mode. Before sending // this command, the device needs to be in PC mode (automatically activated @@ -654,8 +673,22 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char device->bigpage = 16; } else if (OCEANIC_COMMON_MATCH (device->base.version, aqualung_i450t_version)) { device->base.layout = &aqualung_i450t_layout; - } else { + } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_default_version)) { device->base.layout = &oceanic_default_layout; + } else { + WARNING (context, "Unsupported device detected!"); + device->base.layout = &oceanic_default_layout; + if (memcmp(device->base.version + 12, "256K", 4) == 0) { + device->base.layout = &oceanic_atom1_layout; + } else if (memcmp(device->base.version + 12, "512K", 4) == 0) { + device->base.layout = &oceanic_default_layout; + } else if (memcmp(device->base.version + 12, "1024", 4) == 0) { + device->base.layout = &oceanic_oc1_layout; + } else if (memcmp(device->base.version + 12, "2048", 4) == 0) { + device->base.layout = &hollis_tx1_layout; + } else { + device->base.layout = &oceanic_default_layout; + } } *out = (dc_device_t*) device; @@ -663,7 +696,7 @@ oceanic_atom2_device_open2 (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -675,13 +708,15 @@ oceanic_atom2_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; oceanic_atom2_device_t *device = (oceanic_atom2_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Send the quit command. oceanic_atom2_quit (device); // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index a85acff..dbf0859 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -78,9 +78,11 @@ #define A300CS 0x454C #define MUNDIAL3 0x4550 #define F11B 0x4554 +#define VISION 0x4556 #define VTX 0x4557 #define I300 0x4559 #define I450T 0x4641 +#define I550T 0x4642 #define NORMAL 0 #define GAUGE 1 @@ -152,7 +154,7 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned model == OCS || model == PROPLUS3 || model == A300 || model == MANTA || model == INSIGHT2 || model == ZEN || - model == I300) { + model == I300 || model == I550T) { parser->headersize -= PAGESIZE; } else if (model == VT4 || model == VT41) { parser->headersize += PAGESIZE; @@ -242,6 +244,8 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim case ATOM31: case A300AI: case OCI: + case I550T: + case VISION: datetime->year = ((p[5] & 0xE0) >> 5) + ((p[7] & 0xE0) >> 2) + 2000; datetime->month = (p[3] & 0x0F); datetime->day = ((p[0] & 0x80) >> 3) + ((p[3] & 0xF0) >> 4); @@ -376,7 +380,7 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser) unsigned int header = headersize - PAGESIZE / 2; unsigned int footer = size - footersize; if (parser->model == VT4 || parser->model == VT41 || - parser->model == A300AI) { + parser->model == A300AI || parser->model == VISION) { header = 3 * PAGESIZE; } @@ -403,7 +407,7 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser) ngasmixes = 1; o2_offset = header + 3; } else if (parser->model == VT4 || parser->model == VT41 || - parser->model == A300AI) { + parser->model == A300AI || parser->model == VISION) { o2_offset = header + 4; ngasmixes = 4; } else if (parser->model == OCI) { @@ -504,7 +508,7 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns parser->model == MUNDIAL3) *((double *) value) = array_uint16_le (data + 4) / 16.0 * FEET; else - *((double *) value) = array_uint16_le (data + parser->footer + 4) / 16.0 * FEET; + *((double *) value) = (array_uint16_le (data + parser->footer + 4) & 0x0FFF) / 16.0 * FEET; break; case DC_FIELD_GASMIX_COUNT: *((unsigned int *) value) = parser->ngasmixes; @@ -580,7 +584,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ unsigned int samplerate = 1; if (parser->mode != FREEDIVE) { unsigned int idx = 0x17; - if (parser->model == A300CS || parser->model == VTX) + if (parser->model == A300CS || parser->model == VTX || + parser->model == I450T) idx = 0x1f; switch (data[idx] & 0x03) { case 0: @@ -764,16 +769,19 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ temperature = data[offset + 3]; } else if (parser->model == OCS || parser->model == TX1) { temperature = data[offset + 1]; - } else if (parser->model == VT4 || parser->model == VT41 || parser->model == ATOM3 || parser->model == ATOM31 || parser->model == A300AI) { + } else if (parser->model == VT4 || parser->model == VT41 || + parser->model == ATOM3 || parser->model == ATOM31 || + parser->model == A300AI || parser->model == VISION) { temperature = ((data[offset + 7] & 0xF0) >> 4) | ((data[offset + 7] & 0x0C) << 2) | ((data[offset + 5] & 0x0C) << 4); } else if (parser->model == A300CS || parser->model == VTX) { temperature = data[offset + 11]; } else { unsigned int sign; - if (parser->model == DG03 || parser->model == PROPLUS3) + if (parser->model == DG03 || parser->model == PROPLUS3 || + parser->model == I550T) sign = (~data[offset + 5] & 0x04) >> 2; else if (parser->model == VOYAGER2G || parser->model == AMPHOS || - parser->model == AMPHOSAIR) + parser->model == AMPHOSAIR || parser->model == ZENAIR) sign = (data[offset + 5] & 0x04) >> 2; else if (parser->model == ATOM2 || parser->model == PROPLUS21 || parser->model == EPICA || parser->model == EPICB || @@ -801,7 +809,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ parser->model == ATOM3 || parser->model == ATOM31 || parser->model == ZENAIR ||parser->model == A300AI || parser->model == DG03 || parser->model == PROPLUS3 || - parser->model == AMPHOSAIR) + parser->model == AMPHOSAIR || parser->model == I550T || + parser->model == VISION) pressure = (((data[offset + 0] & 0x03) << 8) + data[offset + 1]) * 5; else if (parser->model == TX1 || parser->model == A300CS || parser->model == VTX) pressure = array_uint16_le (data + offset + 4); @@ -870,6 +879,14 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ decostop = data[offset + 10]; decotime = array_uint16_le(data + offset + 6); have_deco = 1; + } else if (parser->model == ATOM31 || parser->model == VISION) { + decostop = (data[offset + 5] & 0xF0) >> 4; + decotime = array_uint16_le(data + offset + 4) & 0x03FF; + have_deco = 1; + } else if (parser->model == I550T) { + decostop = (data[offset + 7] & 0xF0) >> 4; + decotime = array_uint16_le(data + offset + 6) & 0x03FF; + have_deco = 1; } if (have_deco) { if (decostop) { @@ -883,6 +900,26 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ if (callback) callback (DC_SAMPLE_DECO, sample, userdata); } + unsigned int have_rbt = 0; + unsigned int rbt = 0; + if (parser->model == ATOM31) { + rbt = array_uint16_le(data + offset + 6) & 0x01FF; + have_rbt = 1; + } else if (parser->model == I450T) { + rbt = array_uint16_le(data + offset + 8) & 0x01FF; + have_rbt = 1; + } else if (parser->model == I550T) { + rbt = array_uint16_le(data + offset + 4) & 0x03FF; + have_rbt = 1; + } else if (parser->model == VISION) { + rbt = array_uint16_le(data + offset + 6) & 0x03FF; + have_rbt = 1; + } + if (have_rbt) { + sample.rbt = rbt; + if (callback) callback (DC_SAMPLE_RBT, sample, userdata); + } + complete = 1; } diff --git a/src/oceanic_common.c b/src/oceanic_common.c index a1d11fa..a463038 100644 --- a/src/oceanic_common.c +++ b/src/oceanic_common.c @@ -29,12 +29,15 @@ #include "ringbuffer.h" #include "array.h" +#define VTABLE(abstract) ((oceanic_common_device_vtable_t *) abstract->vtable) + #define RB_LOGBOOK_DISTANCE(a,b,l) ringbuffer_distance (a, b, 0, l->rb_logbook_begin, l->rb_logbook_end) #define RB_LOGBOOK_INCR(a,b,l) ringbuffer_increment (a, b, l->rb_logbook_begin, l->rb_logbook_end) #define RB_PROFILE_DISTANCE(a,b,l) ringbuffer_distance (a, b, 0, l->rb_profile_begin, l->rb_profile_end) #define RB_PROFILE_INCR(a,b,l) ringbuffer_increment (a, b, l->rb_profile_begin, l->rb_profile_end) +#define INVALID 0 static unsigned int ifloor (unsigned int x, unsigned int n) @@ -187,53 +190,21 @@ oceanic_common_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) dc_status_t -oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata) +oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook) { oceanic_common_device_t *device = (oceanic_common_device_t *) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; assert (device != NULL); assert (device->layout != NULL); assert (device->layout->rb_logbook_entry_size <= sizeof (device->fingerprint)); + assert (progress != NULL); const oceanic_common_layout_t *layout = device->layout; - // Enable progress notifications. - dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; - progress.maximum = 2 * PAGESIZE + - (layout->rb_profile_end - layout->rb_profile_begin) + - (layout->rb_logbook_end - layout->rb_logbook_begin); - if (layout->rb_logbook_begin == layout->rb_logbook_end) { - progress.maximum -= PAGESIZE; - } - device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); - - // Emit a vendor event. - dc_event_vendor_t vendor; - vendor.data = device->version; - vendor.size = sizeof (device->version); - device_event_emit (abstract, DC_EVENT_VENDOR, &vendor); - - // Read the device id. - unsigned char id[PAGESIZE] = {0}; - dc_status_t rc = dc_device_read (abstract, layout->cf_devinfo, id, sizeof (id)); - if (rc != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to read the memory page."); - return rc; - } - - // Update and emit a progress event. - progress.current += PAGESIZE; - device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); - - // Emit a device info event. - dc_event_devinfo_t devinfo; - devinfo.model = array_uint16_be (id + 8); - devinfo.firmware = 0; - if (layout->pt_mode_global == 0) - devinfo.serial = bcd2dec (id[10]) * 10000 + bcd2dec (id[11]) * 100 + bcd2dec (id[12]); - else - devinfo.serial = id[11] * 10000 + id[12] * 100 + id[13]; - device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); + // Erase the buffer. + if (!dc_buffer_clear (logbook)) + return DC_STATUS_NOMEMORY; // For devices without a logbook ringbuffer, downloading dives isn't // possible. This is not considered a fatal error, but handled as if there @@ -258,7 +229,8 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac rb_logbook_last < layout->rb_logbook_begin || rb_logbook_last >= layout->rb_logbook_end) { - ERROR (abstract->context, "Invalid logbook pointer detected (0x%04x 0x%04x).", rb_logbook_first, rb_logbook_last); + ERROR (abstract->context, "Invalid logbook pointer detected (0x%04x 0x%04x).", + rb_logbook_first, rb_logbook_last); return DC_STATUS_DATAFORMAT; } @@ -306,22 +278,23 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac int unaligned = (rb_logbook_entry_end != rb_logbook_page_end); // Update and emit a progress event. - progress.current += PAGESIZE; - progress.maximum = 2 * PAGESIZE + - (layout->rb_profile_end - layout->rb_profile_begin) + - rb_logbook_page_size; - device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); + progress->current += PAGESIZE; + progress->maximum += PAGESIZE; + progress->maximum -= (layout->rb_logbook_end - layout->rb_logbook_begin) - rb_logbook_page_size; + device_event_emit (abstract, DC_EVENT_PROGRESS, progress); // Exit if there are no dives. if (rb_logbook_page_size == 0) { return DC_STATUS_SUCCESS; } - // Memory buffer for the logbook entries. - unsigned char *logbooks = (unsigned char *) malloc (rb_logbook_page_size); - if (logbooks == NULL) + // Allocate memory for the logbook entries. + if (!dc_buffer_resize (logbook, rb_logbook_page_size)) return DC_STATUS_NOMEMORY; + // Cache the logbook pointer. + unsigned char *logbooks = dc_buffer_get_data (logbook); + // Since entries are not necessary aligned on page boundaries, // the memory buffer may contain padding entries on both sides. // The memory area which contains the valid entries is marked @@ -333,13 +306,6 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac end -= rb_logbook_page_end - rb_logbook_entry_end; } - // Error status for delayed errors. - dc_status_t status = DC_STATUS_SUCCESS; - - // Keep track of the previous dive. - unsigned int remaining = layout->rb_profile_end - layout->rb_profile_begin; - unsigned int previous = 0; - // The logbook ringbuffer is read backwards to retrieve the most recent // entries first. If an already downloaded entry is identified (by means // of its fingerprint), the transfer is aborted immediately to reduce @@ -368,13 +334,13 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac // Read the logbook page. rc = dc_device_read (abstract, address, logbooks + offset, len); if (rc != DC_STATUS_SUCCESS) { - free (logbooks); + ERROR (abstract->context, "Failed to read the memory page."); return rc; } // Update and emit a progress event. - progress.current += len; - device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); + progress->current += len; + device_event_emit (abstract, DC_EVENT_PROGRESS, progress); // A full ringbuffer needs some special treatment to avoid // having to download the first/last page twice. When a full @@ -421,47 +387,6 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac break; } - // Check for invalid ringbuffer pointers. Such pointers shouldn't - // be present, but some devices appear to have them anyway. In that - // case the error is not returned immediately, but delayed until the - // end of the download. With this approach we can download at least - // the dives before the problematic logbook entry. - unsigned int rb_entry_first = get_profile_first (logbooks + current, layout); - unsigned int rb_entry_last = get_profile_last (logbooks + current, layout); - if (rb_entry_first < layout->rb_profile_begin || - rb_entry_first >= layout->rb_profile_end || - rb_entry_last < layout->rb_profile_begin || - rb_entry_last >= layout->rb_profile_end) - { - ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).", rb_entry_first, rb_entry_last); - status = DC_STATUS_DATAFORMAT; - begin = current + layout->rb_logbook_entry_size; - abort = 1; - break; - } - - // Get the profile pointers. - unsigned int rb_entry_end = RB_PROFILE_INCR (rb_entry_last, PAGESIZE, layout); - unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_first, rb_entry_last, layout) + PAGESIZE; - - // Skip gaps between the profiles. - unsigned int gap = 0; - if (previous && rb_entry_end != previous) { - WARNING (abstract->context, "Profiles are not continuous."); - gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout); - } - - // Make sure the profile size is valid. - if (rb_entry_size + gap > remaining) { - WARNING (abstract->context, "Unexpected profile size."); - begin = current + layout->rb_logbook_entry_size; - abort = 1; - break; - } - - remaining -= rb_entry_size + gap; - previous = rb_entry_first; - // Compare the fingerprint to identify previously downloaded entries. if (memcmp (logbooks + current, device->fingerprint, layout->rb_logbook_entry_size) == 0) { begin = current + layout->rb_logbook_entry_size; @@ -475,55 +400,72 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac break; } - // Exit if there are no (new) dives. - if (begin == end) { - free (logbooks); - return status; - } + // Update and emit a progress event. + progress->maximum -= rb_logbook_page_size - nbytes; + device_event_emit (abstract, DC_EVENT_PROGRESS, progress); - // Calculate the total amount of bytes in the profile ringbuffer, - // based on the pointers in the first and last logbook entry. - unsigned int rb_profile_first = get_profile_first (logbooks + begin, layout); - unsigned int rb_profile_last = get_profile_last (logbooks + end - layout->rb_logbook_entry_size, layout); - unsigned int rb_profile_end = RB_PROFILE_INCR (rb_profile_last, PAGESIZE, layout); - unsigned int rb_profile_size = RB_PROFILE_DISTANCE (rb_profile_first, rb_profile_last, layout) + PAGESIZE; + dc_buffer_slice (logbook, begin, end - begin); - // At this point, we know the exact amount of data - // that needs to be transfered for the profiles. - progress.maximum = progress.current + rb_profile_size; + return DC_STATUS_SUCCESS; +} - // Memory buffer for the profile data. - unsigned char *profiles = (unsigned char *) malloc (rb_profile_size + (end - begin)); - if (profiles == NULL) { - free (logbooks); - return DC_STATUS_NOMEMORY; - } - // When using multipage reads, the last packet can contain data from more - // than one dive. Therefore, the remaining data of this package (and its - // size) needs to be preserved for the next dive. - unsigned int available = 0; +dc_status_t +oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata) +{ + oceanic_common_device_t *device = (oceanic_common_device_t *) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; - // Keep track of the previous dive. - remaining = rb_profile_size; - previous = rb_profile_end; + assert (device != NULL); + assert (device->layout != NULL); + assert (device->layout->rb_logbook_entry_size <= sizeof (device->fingerprint)); + assert (progress != NULL); + + const oceanic_common_layout_t *layout = device->layout; + + // Cache the logbook pointer and size. + const unsigned char *logbooks = dc_buffer_get_data (logbook); + unsigned int rb_logbook_size = dc_buffer_get_size (logbook); + + // Go through the logbook entries a first time, to get the end of + // profile pointer and calculate the total amount of bytes in the + // profile ringbuffer. + unsigned int rb_profile_end = INVALID; + unsigned int rb_profile_size = 0; // Traverse the logbook ringbuffer backwards to retrieve the most recent // dives first. The logbook ringbuffer is linearized at this point, so // we do not have to take into account any memory wrapping near the end // of the memory buffer. - current = end; - offset = rb_profile_size + (end - begin); - address = previous; - while (current != begin) { + unsigned int remaining = layout->rb_profile_end - layout->rb_profile_begin; + unsigned int previous = rb_profile_end; + unsigned int entry = rb_logbook_size; + while (entry) { // Move to the start of the current entry. - current -= layout->rb_logbook_entry_size; + entry -= layout->rb_logbook_entry_size; // Get the profile pointers. - unsigned int rb_entry_first = get_profile_first (logbooks + current, layout); - unsigned int rb_entry_last = get_profile_last (logbooks + current, layout); - unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_first, rb_entry_last, layout) + PAGESIZE; + unsigned int rb_entry_first = get_profile_first (logbooks + entry, layout); + unsigned int rb_entry_last = get_profile_last (logbooks + entry, layout); + if (rb_entry_first < layout->rb_profile_begin || + rb_entry_first >= layout->rb_profile_end || + rb_entry_last < layout->rb_profile_begin || + rb_entry_last >= layout->rb_profile_end) + { + ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).", + rb_entry_first, rb_entry_last); + break; + } + + // Calculate the end pointer and the number of bytes. unsigned int rb_entry_end = RB_PROFILE_INCR (rb_entry_last, PAGESIZE, layout); + unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_first, rb_entry_last, layout) + PAGESIZE; + + // Take the end pointer of the most recent logbook entry as the + // end of profile pointer. + if (rb_profile_end == INVALID) { + rb_profile_end = previous = rb_entry_end; + } // Skip gaps between the profiles. unsigned int gap = 0; @@ -532,6 +474,81 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout); } + // Make sure the profile size is valid. + if (rb_entry_size + gap > remaining) { + WARNING (abstract->context, "Unexpected profile size."); + break; + } + + // Update the total profile size. + rb_profile_size += rb_entry_size + gap; + + remaining -= rb_entry_size + gap; + previous = rb_entry_first; + } + + // At this point, we know the exact amount of data + // that needs to be transfered for the profiles. + progress->maximum -= (layout->rb_profile_end - layout->rb_profile_begin) - rb_profile_size; + device_event_emit (abstract, DC_EVENT_PROGRESS, progress); + + // Memory buffer for the profile data. + unsigned char *profiles = (unsigned char *) malloc (rb_profile_size + rb_logbook_size); + if (profiles == NULL) { + return DC_STATUS_NOMEMORY; + } + + // Keep track of the current position. + unsigned int offset = rb_profile_size + rb_logbook_size; + unsigned int address = rb_profile_end; + + // When using multipage reads, the last packet can contain data from more + // than one dive. Therefore, the remaining data of this package (and its + // size) needs to be preserved for the next dive. + unsigned int available = 0; + + // Traverse the logbook ringbuffer backwards to retrieve the most recent + // dives first. The logbook ringbuffer is linearized at this point, so + // we do not have to take into account any memory wrapping near the end + // of the memory buffer. + remaining = rb_profile_size; + previous = rb_profile_end; + entry = rb_logbook_size; + while (entry) { + // Move to the start of the current entry. + entry -= layout->rb_logbook_entry_size; + + // Get the profile pointers. + unsigned int rb_entry_first = get_profile_first (logbooks + entry, layout); + unsigned int rb_entry_last = get_profile_last (logbooks + entry, layout); + if (rb_entry_first < layout->rb_profile_begin || + rb_entry_first >= layout->rb_profile_end || + rb_entry_last < layout->rb_profile_begin || + rb_entry_last >= layout->rb_profile_end) + { + ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).", + rb_entry_first, rb_entry_last); + free (profiles); + return DC_STATUS_DATAFORMAT; + } + + // Calculate the end pointer and the number of bytes. + unsigned int rb_entry_end = RB_PROFILE_INCR (rb_entry_last, PAGESIZE, layout); + unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_first, rb_entry_last, layout) + PAGESIZE; + + // Skip gaps between the profiles. + unsigned int gap = 0; + if (rb_entry_end != previous) { + WARNING (abstract->context, "Profiles are not continuous."); + gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout); + } + + // Make sure the profile size is valid. + if (rb_entry_size + gap > remaining) { + WARNING (abstract->context, "Unexpected profile size."); + break; + } + // Read the profile data. unsigned int nbytes = available; while (nbytes < rb_entry_size + gap) { @@ -553,14 +570,13 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac // Read the profile page. rc = dc_device_read (abstract, address, profiles + offset, len); if (rc != DC_STATUS_SUCCESS) { - free (logbooks); free (profiles); return rc; } // Update and emit a progress event. - progress.current += len; - device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); + progress->current += len; + device_event_emit (abstract, DC_EVENT_PROGRESS, progress); nbytes += len; } @@ -575,18 +591,97 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac if (available) memmove (profiles + offset - layout->rb_logbook_entry_size, profiles + offset, available); offset -= layout->rb_logbook_entry_size; - memcpy (profiles + offset + available, logbooks + current, layout->rb_logbook_entry_size); + memcpy (profiles + offset + available, logbooks + entry, layout->rb_logbook_entry_size); unsigned char *p = profiles + offset + available; if (callback && !callback (p, rb_entry_size + layout->rb_logbook_entry_size, p, layout->rb_logbook_entry_size, userdata)) { - free (logbooks); - free (profiles); - return DC_STATUS_SUCCESS; + break; } } - free (logbooks); free (profiles); - return status; + return DC_STATUS_SUCCESS; +} + + +dc_status_t +oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata) +{ + oceanic_common_device_t *device = (oceanic_common_device_t *) abstract; + + assert (device != NULL); + assert (device->layout != NULL); + + const oceanic_common_layout_t *layout = device->layout; + + // Enable progress notifications. + dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; + progress.maximum = PAGESIZE + + (layout->rb_logbook_end - layout->rb_logbook_begin) + + (layout->rb_profile_end - layout->rb_profile_begin); + device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); + + // Emit a vendor event. + dc_event_vendor_t vendor; + vendor.data = device->version; + vendor.size = sizeof (device->version); + device_event_emit (abstract, DC_EVENT_VENDOR, &vendor); + + // Read the device id. + unsigned char id[PAGESIZE] = {0}; + dc_status_t rc = dc_device_read (abstract, layout->cf_devinfo, id, sizeof (id)); + if (rc != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to read the memory page."); + return rc; + } + + // Update and emit a progress event. + progress.current += PAGESIZE; + device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); + + // Emit a device info event. + dc_event_devinfo_t devinfo; + devinfo.model = array_uint16_be (id + 8); + devinfo.firmware = 0; + if (layout->pt_mode_serial == 0) + devinfo.serial = bcd2dec (id[10]) * 10000 + bcd2dec (id[11]) * 100 + bcd2dec (id[12]); + else if (layout->pt_mode_serial == 1) + devinfo.serial = id[11] * 10000 + id[12] * 100 + id[13]; + else + devinfo.serial = + (id[11] & 0x0F) * 100000 + ((id[11] & 0xF0) >> 4) * 10000 + + (id[12] & 0x0F) * 1000 + ((id[12] & 0xF0) >> 4) * 100 + + (id[13] & 0x0F) * 10 + ((id[13] & 0xF0) >> 4) * 1; + device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); + + // Memory buffer for the logbook data. + dc_buffer_t *logbook = dc_buffer_new (0); + if (logbook == NULL) { + return DC_STATUS_NOMEMORY; + } + + // Download the logbook ringbuffer. + rc = VTABLE(abstract)->logbook (abstract, &progress, logbook); + if (rc != DC_STATUS_SUCCESS) { + dc_buffer_free (logbook); + return rc; + } + + // Exit if there are no (new) dives. + if (dc_buffer_get_size (logbook) == 0) { + dc_buffer_free (logbook); + return DC_STATUS_SUCCESS; + } + + // Download the profile ringbuffer. + rc = VTABLE(abstract)->profile (abstract, &progress, logbook, callback, userdata); + if (rc != DC_STATUS_SUCCESS) { + dc_buffer_free (logbook); + return rc; + } + + dc_buffer_free (logbook); + + return DC_STATUS_SUCCESS; } diff --git a/src/oceanic_common.h b/src/oceanic_common.h index e5e53f0..1b8ed08 100644 --- a/src/oceanic_common.h +++ b/src/oceanic_common.h @@ -55,6 +55,7 @@ typedef struct oceanic_common_layout_t { // 12-bit values or two 16-bit values with each 4 bits padding). unsigned int pt_mode_global; unsigned int pt_mode_logbook; + unsigned int pt_mode_serial; } oceanic_common_layout_t; typedef struct oceanic_common_device_t { @@ -65,6 +66,12 @@ typedef struct oceanic_common_device_t { unsigned int multipage; } oceanic_common_device_t; +typedef struct oceanic_common_device_vtable_t { + dc_device_vtable_t base; + dc_status_t (*logbook) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook); + dc_status_t (*profile) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata); +} oceanic_common_device_vtable_t; + typedef unsigned char oceanic_common_version_t[PAGESIZE + 1]; int @@ -73,6 +80,12 @@ oceanic_common_match (const unsigned char *version, const oceanic_common_version void oceanic_common_device_init (oceanic_common_device_t *device); +dc_status_t +oceanic_common_device_logbook (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook); + +dc_status_t +oceanic_common_device_profile (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata); + dc_status_t oceanic_common_device_set_fingerprint (dc_device_t *device, const unsigned char data[], unsigned int size); diff --git a/src/oceanic_veo250.c b/src/oceanic_veo250.c index 653d51e..c8c1215 100644 --- a/src/oceanic_veo250.c +++ b/src/oceanic_veo250.c @@ -31,40 +31,39 @@ #include "ringbuffer.h" #include "checksum.h" -#define ISINSTANCE(device) dc_device_isinstance((device), &oceanic_veo250_device_vtable) +#define ISINSTANCE(device) dc_device_isinstance((device), &oceanic_veo250_device_vtable.base) #define MAXRETRIES 2 #define MULTIPAGE 4 -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define ACK 0x5A #define NAK 0xA5 typedef struct oceanic_veo250_device_t { oceanic_common_device_t base; - serial_t *port; + dc_serial_t *port; unsigned int last; } oceanic_veo250_device_t; static dc_status_t oceanic_veo250_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); static dc_status_t oceanic_veo250_device_close (dc_device_t *abstract); -static const dc_device_vtable_t oceanic_veo250_device_vtable = { - sizeof(oceanic_veo250_device_t), - DC_FAMILY_OCEANIC_VEO250, - oceanic_common_device_set_fingerprint, /* set_fingerprint */ - oceanic_veo250_device_read, /* read */ - NULL, /* write */ - oceanic_common_device_dump, /* dump */ - oceanic_common_device_foreach, /* foreach */ - oceanic_veo250_device_close /* close */ +static const oceanic_common_device_vtable_t oceanic_veo250_device_vtable = { + { + sizeof(oceanic_veo250_device_t), + DC_FAMILY_OCEANIC_VEO250, + oceanic_common_device_set_fingerprint, /* set_fingerprint */ + oceanic_veo250_device_read, /* read */ + NULL, /* write */ + oceanic_common_device_dump, /* dump */ + oceanic_common_device_foreach, /* foreach */ + oceanic_veo250_device_close /* close */ + }, + oceanic_common_device_logbook, + oceanic_common_device_profile, }; -static const oceanic_common_version_t oceanic_vtpro_version[] = { +static const oceanic_common_version_t oceanic_veo250_version[] = { {"GENREACT \0\0 256K"}, {"VEO 200 R\0\0 256K"}, {"VEO 250 R\0\0 256K"}, @@ -84,34 +83,36 @@ static const oceanic_common_layout_t oceanic_veo250_layout = { 0x0600, /* rb_profile_begin */ 0x8000, /* rb_profile_end */ 1, /* pt_mode_global */ - 1 /* pt_mode_logbook */ + 1, /* pt_mode_logbook */ + 1, /* pt_mode_serial */ }; static dc_status_t oceanic_veo250_send (oceanic_veo250_device_t *device, const unsigned char command[], unsigned int csize) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; // Discard garbage bytes. - serial_flush (device->port, SERIAL_QUEUE_INPUT); + dc_serial_purge (device->port, DC_DIRECTION_INPUT); // Send the command to the dive computer. - int n = serial_write (device->port, command, csize); - if (n != csize) { + status = dc_serial_write (device->port, command, csize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Receive the response (ACK/NAK) of the dive computer. unsigned char response = NAK; - n = serial_read (device->port, &response, 1); - if (n != 1) { + status = dc_serial_read (device->port, &response, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the response of the dive computer. @@ -127,6 +128,7 @@ oceanic_veo250_send (oceanic_veo250_device_t *device, const unsigned char comman static dc_status_t oceanic_veo250_transfer (oceanic_veo250_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Send the command to the device. If the device responds with an @@ -146,14 +148,14 @@ oceanic_veo250_transfer (oceanic_veo250_device_t *device, const unsigned char co return rc; // Delay the next attempt. - serial_sleep (device->port, 100); + dc_serial_sleep (device->port, 100); } // Receive the answer of the dive computer. - int n = serial_read (device->port, answer, asize); - if (n != asize) { + status = dc_serial_read (device->port, answer, asize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the last byte of the answer. @@ -169,24 +171,26 @@ oceanic_veo250_transfer (oceanic_veo250_device_t *device, const unsigned char co static dc_status_t oceanic_veo250_init (oceanic_veo250_device_t *device) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Send the command to the dive computer. unsigned char command[2] = {0x55, 0x00}; - int n = serial_write (device->port, command, sizeof (command)); - if (n != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Receive the answer of the dive computer. + size_t n = 0; unsigned char answer[13] = {0}; - n = serial_read (device->port, answer, sizeof (answer)); - if (n != sizeof (answer)) { + status = dc_serial_read (device->port, answer, sizeof (answer), &n); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); if (n == 0) return DC_STATUS_SUCCESS; - return EXITCODE (n); + return status; } // Verify the answer. @@ -205,14 +209,15 @@ oceanic_veo250_init (oceanic_veo250_device_t *device) static dc_status_t oceanic_veo250_quit (oceanic_veo250_device_t *device) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Send the command to the dive computer. unsigned char command[2] = {0x98, 0x00}; - int n = serial_write (device->port, command, sizeof (command)); - if (n != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } return DC_STATUS_SUCCESS; @@ -229,7 +234,7 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (oceanic_veo250_device_t *) dc_device_allocate (context, &oceanic_veo250_device_vtable); + device = (oceanic_veo250_device_t *) dc_device_allocate (context, &oceanic_veo250_device_vtable.base); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -239,7 +244,6 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char oceanic_common_device_init (&device->base); // Override the base class values. - device->base.layout = &oceanic_veo250_layout; device->base.multipage = MULTIPAGE; // Set the default values. @@ -247,41 +251,45 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char device->last = 0; // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (9600 8N1). - rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (3000 ms). - if (serial_set_timeout (device->port, 3000) == -1) { + status = dc_serial_set_timeout (device->port, 3000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } - // Set the DTR and RTS lines. - if (serial_set_dtr (device->port, 1) == -1 || - serial_set_rts (device->port, 1) == -1) { - ERROR (context, "Failed to set the DTR/RTS line."); - status = DC_STATUS_IO; + // Set the DTR line. + status = dc_serial_set_dtr (device->port, 1); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to set the DTR line."); + goto error_close; + } + + // Set the RTS line. + status = dc_serial_set_rts (device->port, 1); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to set the RTS line."); goto error_close; } // Give the interface 100 ms to settle and draw power up. - serial_sleep (device->port, 100); + dc_serial_sleep (device->port, 100); // Make sure everything is in a sane state. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); // Initialize the data cable (PPS mode). status = oceanic_veo250_init (device); @@ -290,7 +298,7 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char } // Delay the sending of the version command. - serial_sleep (device->port, 100); + dc_serial_sleep (device->port, 100); // Switch the device from surface mode into download mode. Before sending // this command, the device needs to be in PC mode (manually activated by @@ -300,12 +308,20 @@ oceanic_veo250_device_open (dc_device_t **out, dc_context_t *context, const char goto error_close; } + // Override the base class values. + if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_veo250_version)) { + device->base.layout = &oceanic_veo250_layout; + } else { + WARNING (context, "Unsupported device detected!"); + device->base.layout = &oceanic_veo250_layout; + } + *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -317,13 +333,15 @@ oceanic_veo250_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; oceanic_veo250_device_t *device = (oceanic_veo250_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Switch the device back to surface mode. oceanic_veo250_quit (device); // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; diff --git a/src/oceanic_veo250_parser.c b/src/oceanic_veo250_parser.c index a300af8..7be86c4 100644 --- a/src/oceanic_veo250_parser.c +++ b/src/oceanic_veo250_parser.c @@ -162,7 +162,7 @@ oceanic_veo250_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, un if (value) { switch (type) { case DC_FIELD_DIVETIME: - *((unsigned int *) value) = data[footer + 3] * 60; + *((unsigned int *) value) = data[footer + 3] * 60 + data[footer + 4] * 3600; break; case DC_FIELD_MAXDEPTH: *((double *) value) = parser->maxdepth; diff --git a/src/oceanic_vtpro.c b/src/oceanic_vtpro.c index 040f23f..22d042b 100644 --- a/src/oceanic_vtpro.c +++ b/src/oceanic_vtpro.c @@ -21,6 +21,7 @@ #include // memcpy #include // malloc, free +#include #include @@ -30,38 +31,48 @@ #include "serial.h" #include "ringbuffer.h" #include "checksum.h" +#include "array.h" -#define ISINSTANCE(device) dc_device_isinstance((device), &oceanic_vtpro_device_vtable) +#define ISINSTANCE(device) dc_device_isinstance((device), &oceanic_vtpro_device_vtable.base) #define MAXRETRIES 2 #define MULTIPAGE 4 -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define ACK 0x5A #define NAK 0xA5 #define END 0x51 +#define AERIS500AI 0x4151 + +typedef enum oceanic_vtpro_protocol_t { + MOD, + INTR, +} oceanic_vtpro_protocol_t; + typedef struct oceanic_vtpro_device_t { oceanic_common_device_t base; - serial_t *port; + dc_serial_t *port; + unsigned int model; + oceanic_vtpro_protocol_t protocol; } oceanic_vtpro_device_t; +static dc_status_t oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook); static dc_status_t oceanic_vtpro_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); static dc_status_t oceanic_vtpro_device_close (dc_device_t *abstract); -static const dc_device_vtable_t oceanic_vtpro_device_vtable = { - sizeof(oceanic_vtpro_device_t), - DC_FAMILY_OCEANIC_VTPRO, - oceanic_common_device_set_fingerprint, /* set_fingerprint */ - oceanic_vtpro_device_read, /* read */ - NULL, /* write */ - oceanic_common_device_dump, /* dump */ - oceanic_common_device_foreach, /* foreach */ - oceanic_vtpro_device_close /* close */ +static const oceanic_common_device_vtable_t oceanic_vtpro_device_vtable = { + { + sizeof(oceanic_vtpro_device_t), + DC_FAMILY_OCEANIC_VTPRO, + oceanic_common_device_set_fingerprint, /* set_fingerprint */ + oceanic_vtpro_device_read, /* read */ + NULL, /* write */ + oceanic_common_device_dump, /* dump */ + oceanic_common_device_foreach, /* foreach */ + oceanic_vtpro_device_close /* close */ + }, + oceanic_vtpro_device_logbook, + oceanic_common_device_profile, }; static const oceanic_common_version_t oceanic_vtpro_version[] = { @@ -87,7 +98,8 @@ static const oceanic_common_layout_t oceanic_vtpro_layout = { 0x0440, /* rb_profile_begin */ 0x8000, /* rb_profile_end */ 0, /* pt_mode_global */ - 0 /* pt_mode_logbook */ + 0, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; static const oceanic_common_layout_t oceanic_wisdom_layout = { @@ -100,31 +112,46 @@ static const oceanic_common_layout_t oceanic_wisdom_layout = { 0x05D0, /* rb_profile_begin */ 0x8000, /* rb_profile_end */ 0, /* pt_mode_global */ - 0 /* pt_mode_logbook */ + 0, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ }; +static const oceanic_common_layout_t aeris_500ai_layout = { + 0x20000, /* memsize */ + 0x0000, /* cf_devinfo */ + 0x0110, /* cf_pointers */ + 0x0200, /* rb_logbook_begin */ + 0x0200, /* rb_logbook_end */ + 8, /* rb_logbook_entry_size */ + 0x00200, /* rb_profile_begin */ + 0x20000, /* rb_profile_end */ + 0, /* pt_mode_global */ + 1, /* pt_mode_logbook */ + 2, /* pt_mode_serial */ +}; static dc_status_t oceanic_vtpro_send (oceanic_vtpro_device_t *device, const unsigned char command[], unsigned int csize) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; // Send the command to the dive computer. - int n = serial_write (device->port, command, csize); - if (n != csize) { + status = dc_serial_write (device->port, command, csize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Receive the response (ACK/NAK) of the dive computer. unsigned char response = NAK; - n = serial_read (device->port, &response, 1); - if (n != 1) { + status = dc_serial_read (device->port, &response, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the response of the dive computer. @@ -140,6 +167,7 @@ oceanic_vtpro_send (oceanic_vtpro_device_t *device, const unsigned char command[ static dc_status_t oceanic_vtpro_transfer (oceanic_vtpro_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Send the command to the device. If the device responds with an @@ -159,11 +187,13 @@ oceanic_vtpro_transfer (oceanic_vtpro_device_t *device, const unsigned char comm return rc; } - // Receive the answer of the dive computer. - int n = serial_read (device->port, answer, asize); - if (n != asize) { - ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + if (asize) { + // Receive the answer of the dive computer. + status = dc_serial_read (device->port, answer, asize, NULL); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to receive the answer."); + return status; + } } return DC_STATUS_SUCCESS; @@ -173,29 +203,32 @@ oceanic_vtpro_transfer (oceanic_vtpro_device_t *device, const unsigned char comm static dc_status_t oceanic_vtpro_init (oceanic_vtpro_device_t *device) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Send the command to the dive computer. - unsigned char command[2] = {0xAA, 0x00}; - int n = serial_write (device->port, command, sizeof (command)); - if (n != sizeof (command)) { + unsigned char command[2][2] = { + {0xAA, 0x00}, + {0x20, 0x00}}; + status = dc_serial_write (device->port, command[device->protocol], sizeof (command[device->protocol]), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Receive the answer of the dive computer. unsigned char answer[13] = {0}; - n = serial_read (device->port, answer, sizeof (answer)); - if (n != sizeof (answer)) { + status = dc_serial_read (device->port, answer, sizeof (answer), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the answer. - const unsigned char response[13] = { - 0x4D, 0x4F, 0x44, 0x2D, 0x2D, 0x4F, 0x4B, - 0x5F, 0x56, 0x32, 0x2E, 0x30, 0x30}; - if (memcmp (answer, response, sizeof (response)) != 0) { + const unsigned char response[2][13] = { + {0x4D, 0x4F, 0x44, 0x2D, 0x2D, 0x4F, 0x4B, 0x5F, 0x56, 0x32, 0x2E, 0x30, 0x30}, + {0x49, 0x4E, 0x54, 0x52, 0x2D, 0x4F, 0x4B, 0x5F, 0x56, 0x31, 0x2E, 0x31, 0x31}}; + if (memcmp (answer, response[device->protocol], sizeof (response[device->protocol])) != 0) { ERROR (abstract->context, "Unexpected answer byte(s)."); return DC_STATUS_PROTOCOL; } @@ -236,9 +269,9 @@ oceanic_vtpro_calibrate (oceanic_vtpro_device_t *device) // device needs approximately 6 seconds to respond. unsigned char answer[2] = {0}; unsigned char command[2] = {0x18, 0x00}; - serial_set_timeout (device->port, 9000); + dc_serial_set_timeout (device->port, 9000); dc_status_t rc = oceanic_vtpro_transfer (device, command, sizeof (command), answer, sizeof (answer)); - serial_set_timeout (device->port, 3000); + dc_serial_set_timeout (device->port, 3000); if (rc != DC_STATUS_SUCCESS) return rc; @@ -251,9 +284,115 @@ oceanic_vtpro_calibrate (oceanic_vtpro_device_t *device) return DC_STATUS_SUCCESS; } +static dc_status_t +oceanic_aeris500ai_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook) +{ + dc_status_t rc = DC_STATUS_SUCCESS; + oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract; + + assert (device != NULL); + assert (device->base.layout != NULL); + assert (device->base.layout->rb_logbook_entry_size == PAGESIZE / 2); + assert (device->base.layout->rb_logbook_begin == device->base.layout->rb_logbook_end); + assert (progress != NULL); + + const oceanic_common_layout_t *layout = device->base.layout; + + // Erase the buffer. + if (!dc_buffer_clear (logbook)) + return DC_STATUS_NOMEMORY; + + // Read the pointer data. + unsigned char pointers[PAGESIZE] = {0}; + rc = oceanic_vtpro_device_read (abstract, layout->cf_pointers, pointers, sizeof (pointers)); + if (rc != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to read the memory page."); + return rc; + } + + // Get the logbook pointers. + unsigned int last = pointers[0x03]; + + // Update and emit a progress event. + progress->current += PAGESIZE; + progress->maximum += PAGESIZE + (last + 1) * PAGESIZE / 2; + device_event_emit (abstract, DC_EVENT_PROGRESS, progress); + + // Allocate memory for the logbook entries. + if (!dc_buffer_reserve (logbook, (last + 1) * PAGESIZE / 2)) + return DC_STATUS_NOMEMORY; + + // Send the logbook index command. + unsigned char command[] = {0x52, + (last >> 8) & 0xFF, // high + (last ) & 0xFF, // low + 0x00}; + rc = oceanic_vtpro_transfer (device, command, sizeof (command), NULL, 0); + if (rc != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to send the logbook index command."); + return rc; + } + + // Read the logbook index. + for (unsigned int i = 0; i < last + 1; ++i) { + // Receive the answer of the dive computer. + unsigned char answer[PAGESIZE / 2 + 1] = {0}; + rc = dc_serial_read (device->port, answer, sizeof(answer), NULL); + if (rc != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to receive the answer."); + return rc; + } + + // Verify the checksum of the answer. + unsigned char crc = answer[PAGESIZE / 2]; + unsigned char ccrc = checksum_add_uint4 (answer, PAGESIZE / 2, 0x00); + if (crc != ccrc) { + ERROR (abstract->context, "Unexpected answer checksum."); + return DC_STATUS_PROTOCOL; + } + + // Update and emit a progress event. + progress->current += PAGESIZE / 2; + device_event_emit (abstract, DC_EVENT_PROGRESS, progress); + + // Ignore uninitialized entries. + if (array_isequal (answer, PAGESIZE / 2, 0xFF)) { + WARNING (abstract->context, "Uninitialized logbook entries detected!"); + continue; + } + + // Compare the fingerprint to identify previously downloaded entries. + if (memcmp (answer, device->base.fingerprint, PAGESIZE / 2) == 0) { + dc_buffer_clear (logbook); + } else { + dc_buffer_append (logbook, answer, PAGESIZE / 2); + } + } + + return DC_STATUS_SUCCESS; +} + +static dc_status_t +oceanic_vtpro_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook) +{ + oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t *) abstract; + + if (device->model == AERIS500AI) { + return oceanic_aeris500ai_device_logbook (abstract, progress, logbook); + } else { + return oceanic_common_device_logbook (abstract, progress, logbook); + } +} dc_status_t oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char *name) +{ + return oceanic_vtpro_device_open2 (out, context, name, 0); +} + + +dc_status_t +oceanic_vtpro_device_open2 (dc_device_t **out, dc_context_t *context, const char *name, unsigned int model) { dc_status_t status = DC_STATUS_SUCCESS; oceanic_vtpro_device_t *device = NULL; @@ -262,7 +401,7 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_INVALIDARGS; // Allocate memory. - device = (oceanic_vtpro_device_t *) dc_device_allocate (context, &oceanic_vtpro_device_vtable); + device = (oceanic_vtpro_device_t *) dc_device_allocate (context, &oceanic_vtpro_device_vtable.base); if (device == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; @@ -276,43 +415,53 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char // Set the default values. device->port = NULL; + device->model = model; + if (model == AERIS500AI) { + device->protocol = INTR; + } else { + device->protocol = MOD; + } // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (9600 8N1). - rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (3000 ms). - if (serial_set_timeout (device->port, 3000) == -1) { + status = dc_serial_set_timeout (device->port, 3000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } - // Set the DTR and RTS lines. - if (serial_set_dtr (device->port, 1) == -1 || - serial_set_rts (device->port, 1) == -1) { - ERROR (context, "Failed to set the DTR/RTS line."); - status = DC_STATUS_IO; + // Set the DTR line. + status = dc_serial_set_dtr (device->port, 1); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to set the DTR line."); + goto error_close; + } + + // Set the RTS line. + status = dc_serial_set_rts (device->port, 1); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to set the RTS line."); goto error_close; } // Give the interface 100 ms to settle and draw power up. - serial_sleep (device->port, 100); + dc_serial_sleep (device->port, device->protocol == MOD ? 100 : 1000); // Make sure everything is in a sane state. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); // Initialize the data cable (MOD mode). status = oceanic_vtpro_init (device); @@ -337,9 +486,14 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char } // Override the base class values. - if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_wisdom_version)) { + if (model == AERIS500AI) { + device->base.layout = &aeris_500ai_layout; + } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_wisdom_version)) { device->base.layout = &oceanic_wisdom_layout; + } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_vtpro_version)) { + device->base.layout = &oceanic_vtpro_layout; } else { + WARNING (context, "Unsupported device detected!"); device->base.layout = &oceanic_vtpro_layout; } @@ -348,7 +502,7 @@ oceanic_vtpro_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -360,13 +514,15 @@ oceanic_vtpro_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; oceanic_vtpro_device_t *device = (oceanic_vtpro_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Switch the device back to surface mode. oceanic_vtpro_quit (device); // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -427,32 +583,36 @@ oceanic_vtpro_device_version (dc_device_t *abstract, unsigned char data[], unsig return DC_STATUS_PROTOCOL; } - // Obtain the device identification string. This string is - // split over two packets, but we join both parts again. + if (device->protocol == MOD) { + // Obtain the device identification string. This string is + // split over two packets, but we join both parts again. + for (unsigned int i = 0; i < 2; ++i) { + unsigned char command[4] = {0x72, 0x03, i * 0x10, 0x00}; + unsigned char answer[PAGESIZE / 2 + 2] = {0}; + rc = oceanic_vtpro_transfer (device, command, sizeof (command), answer, sizeof (answer)); + if (rc != DC_STATUS_SUCCESS) + return rc; - for (unsigned int i = 0; i < 2; ++i) { - unsigned char command[4] = {0x72, 0x03, i * 0x10, 0x00}; - unsigned char answer[PAGESIZE / 2 + 2] = {0}; - rc = oceanic_vtpro_transfer (device, command, sizeof (command), answer, sizeof (answer)); - if (rc != DC_STATUS_SUCCESS) - return rc; + // Verify the checksum of the answer. + unsigned char crc = answer[PAGESIZE / 2]; + unsigned char ccrc = checksum_add_uint4 (answer, PAGESIZE / 2, 0x00); + if (crc != ccrc) { + ERROR (abstract->context, "Unexpected answer checksum."); + return DC_STATUS_PROTOCOL; + } - // Verify the checksum of the answer. - unsigned char crc = answer[PAGESIZE / 2]; - unsigned char ccrc = checksum_add_uint4 (answer, PAGESIZE / 2, 0x00); - if (crc != ccrc) { - ERROR (abstract->context, "Unexpected answer checksum."); - return DC_STATUS_PROTOCOL; + // Verify the last byte of the answer. + if (answer[PAGESIZE / 2 + 1] != END) { + ERROR (abstract->context, "Unexpected answer byte."); + return DC_STATUS_PROTOCOL; + } + + // Append the answer to the output buffer. + memcpy (data + i * PAGESIZE / 2, answer, PAGESIZE / 2); } - - // Verify the last byte of the answer. - if (answer[PAGESIZE / 2 + 1] != END) { - ERROR (abstract->context, "Unexpected answer byte."); - return DC_STATUS_PROTOCOL; - } - - // Append the answer to the output buffer. - memcpy (data + i * PAGESIZE / 2, answer, PAGESIZE / 2); + } else { + // Return an empty device identification string. + memset (data, 0x00, PAGESIZE); } return DC_STATUS_SUCCESS; diff --git a/src/oceanic_vtpro_parser.c b/src/oceanic_vtpro_parser.c index d2d7919..859025e 100644 --- a/src/oceanic_vtpro_parser.c +++ b/src/oceanic_vtpro_parser.c @@ -31,10 +31,13 @@ #define ISINSTANCE(parser) dc_parser_isinstance((parser), &oceanic_vtpro_parser_vtable) +#define AERIS500AI 0x4151 + typedef struct oceanic_vtpro_parser_t oceanic_vtpro_parser_t; struct oceanic_vtpro_parser_t { dc_parser_t base; + unsigned int model; // Cached fields. unsigned int cached; unsigned int divetime; @@ -59,6 +62,13 @@ static const dc_parser_vtable_t oceanic_vtpro_parser_vtable = { dc_status_t oceanic_vtpro_parser_create (dc_parser_t **out, dc_context_t *context) +{ + return oceanic_vtpro_parser_create2 (out, context, 0); +} + + +dc_status_t +oceanic_vtpro_parser_create2 (dc_parser_t **out, dc_context_t *context, unsigned int model) { oceanic_vtpro_parser_t *parser = NULL; @@ -73,6 +83,7 @@ oceanic_vtpro_parser_create (dc_parser_t **out, dc_context_t *context) } // Set the default values. + parser->model = model; parser->cached = 0; parser->divetime = 0; parser->maxdepth = 0.0; @@ -100,27 +111,41 @@ oceanic_vtpro_parser_set_data (dc_parser_t *abstract, const unsigned char *data, static dc_status_t oceanic_vtpro_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime) { + oceanic_vtpro_parser_t *parser = (oceanic_vtpro_parser_t *) abstract; + if (abstract->size < 8) return DC_STATUS_DATAFORMAT; const unsigned char *p = abstract->data; if (datetime) { - // The logbook entry can only store the last digit of the year field, - // but the full year is also available in the dive header. - if (abstract->size < 40) - datetime->year = bcd2dec (p[4] & 0x0F) + 2000; - else - datetime->year = bcd2dec (((p[32 + 3] & 0xC0) >> 2) + ((p[32 + 2] & 0xF0) >> 4)) + 2000; - datetime->month = (p[4] & 0xF0) >> 4; - datetime->day = bcd2dec (p[3]); - datetime->hour = bcd2dec (p[1] & 0x7F); + // AM/PM bit of the 12-hour clock. + unsigned int pm = 0; + + if (parser->model == AERIS500AI) { + datetime->year = (p[2] & 0x0F) + 1999; + datetime->month = (p[3] & 0xF0) >> 4; + datetime->day = ((p[2] & 0xF0) >> 4) | ((p[3] & 0x02) << 3); + datetime->hour = bcd2dec (p[1] & 0x0F) + 10 * (p[3] & 0x01); + pm = p[3] & 0x08; + } else { + // The logbook entry can only store the last digit of the year field, + // but the full year is also available in the dive header. + if (abstract->size < 40) + datetime->year = bcd2dec (p[4] & 0x0F) + 2000; + else + datetime->year = bcd2dec (((p[32 + 3] & 0xC0) >> 2) + ((p[32 + 2] & 0xF0) >> 4)) + 2000; + datetime->month = (p[4] & 0xF0) >> 4; + datetime->day = bcd2dec (p[3]); + datetime->hour = bcd2dec (p[1] & 0x7F); + pm = p[1] & 0x80; + } datetime->minute = bcd2dec (p[0]); datetime->second = 0; // Convert to a 24-hour clock. datetime->hour %= 12; - if (p[1] & 0x80) + if (pm) datetime->hour += 12; } @@ -153,8 +178,17 @@ oceanic_vtpro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns unsigned int footer = size - PAGESIZE; + unsigned int oxygen = 0; + unsigned int maxdepth = 0; unsigned int beginpressure = array_uint16_le(data + 0x26) & 0x0FFF; unsigned int endpressure = array_uint16_le(data + footer + 0x05) & 0x0FFF; + if (parser->model == AERIS500AI) { + oxygen = (array_uint16_le(data + footer + 2) & 0x0FF0) >> 4; + maxdepth = data[footer + 1]; + } else { + oxygen = data[footer + 3]; + maxdepth = array_uint16_le(data + footer + 0) & 0x0FFF; + } dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_tank_t *tank = (dc_tank_t *) value; @@ -165,15 +199,15 @@ oceanic_vtpro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns *((unsigned int *) value) = parser->divetime; break; case DC_FIELD_MAXDEPTH: - *((double *) value) = (data[footer + 0] + ((data[footer + 1] & 0x0F) << 8)) * FEET; + *((double *) value) = maxdepth * FEET; break; case DC_FIELD_GASMIX_COUNT: *((unsigned int *) value) = 1; break; case DC_FIELD_GASMIX: gasmix->helium = 0.0; - if (data[footer + 3]) - gasmix->oxygen = data[footer + 3] / 100.0; + if (oxygen) + gasmix->oxygen = oxygen / 100.0; else gasmix->oxygen = 0.21; gasmix->nitrogen = 1.0 - gasmix->oxygen - gasmix->helium; @@ -204,6 +238,8 @@ oceanic_vtpro_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns static dc_status_t oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata) { + oceanic_vtpro_parser_t *parser = (oceanic_vtpro_parser_t *) abstract; + const unsigned char *data = abstract->data; unsigned int size = abstract->size; @@ -212,22 +248,18 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ unsigned int time = 0; unsigned int interval = 0; - switch ((data[0x27] >> 4) & 0x07) { - case 0: - interval = 2; - break; - case 1: - interval = 15; - break; - case 2: - interval = 30; - break; - case 3: - interval = 60; - break; - default: - interval = 0; - break; + if (parser->model == AERIS500AI) { + const unsigned int intervals[] = {2, 5, 10, 15, 20, 25, 30}; + unsigned int samplerate = (data[0x27] >> 4); + if (samplerate >= 3 && samplerate <= 9) { + interval = intervals[samplerate - 3]; + } + } else { + const unsigned int intervals[] = {2, 15, 30, 60}; + unsigned int samplerate = (data[0x27] >> 4) & 0x07; + if (samplerate <= 3) { + interval = intervals[samplerate]; + } } // Initialize the state for the timestamp processing. @@ -238,7 +270,8 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ dc_sample_value_t sample = {0}; // Ignore empty samples. - if (array_isequal (data + offset, PAGESIZE / 2, 0x00)) { + if (array_isequal (data + offset, PAGESIZE / 2, 0x00) || + array_isequal (data + offset, PAGESIZE / 2, 0xFF)) { offset += PAGESIZE / 2; continue; } @@ -264,7 +297,8 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ unsigned int idx = offset + PAGESIZE / 2 ; while (idx + PAGESIZE / 2 <= size - PAGESIZE) { // Ignore empty samples. - if (array_isequal (data + idx, PAGESIZE / 2, 0x00)) { + if (array_isequal (data + idx, PAGESIZE / 2, 0x00) || + array_isequal (data + idx, PAGESIZE / 2, 0xFF)) { idx += PAGESIZE / 2; continue; } @@ -312,12 +346,22 @@ oceanic_vtpro_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ if (callback) callback (DC_SAMPLE_VENDOR, sample, userdata); // Depth (ft) - unsigned int depth = data[offset + 3]; + unsigned int depth = 0; + if (parser->model == AERIS500AI) { + depth = (array_uint16_le(data + offset + 2) & 0x0FF0) >> 4; + } else { + depth = data[offset + 3]; + } sample.depth = depth * FEET; if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata); // Temperature (°F) - unsigned int temperature = data[offset + 6]; + unsigned int temperature = 0; + if (parser->model == AERIS500AI) { + temperature = (array_uint16_le(data + offset + 6) & 0x0FF0) >> 4; + } else { + temperature = data[offset + 6]; + } sample.temperature = (temperature - 32.0) * (5.0 / 9.0); if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata); diff --git a/src/parser.c b/src/parser.c index 4ddd064..aaff57f 100644 --- a/src/parser.c +++ b/src/parser.c @@ -43,18 +43,16 @@ #define REACTPROWHITE 0x4354 -dc_status_t -dc_parser_new (dc_parser_t **out, dc_device_t *device) +static dc_status_t +dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t family, unsigned int model, unsigned int serial, unsigned int devtime, dc_ticks_t systime) { dc_status_t rc = DC_STATUS_SUCCESS; dc_parser_t *parser = NULL; - if (out == NULL || device == NULL) + if (out == NULL) return DC_STATUS_INVALIDARGS; - dc_context_t *context = device->context; - - switch (dc_device_get_type (device)) { + switch (family) { case DC_FAMILY_SUUNTO_SOLUTION: rc = suunto_solution_parser_create (&parser, context); break; @@ -62,67 +60,67 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device) rc = suunto_eon_parser_create (&parser, context, 0); break; case DC_FAMILY_SUUNTO_VYPER: - if (device->devinfo.model == 0x01) + if (model == 0x01) rc = suunto_eon_parser_create (&parser, context, 1); else rc = suunto_vyper_parser_create (&parser, context); break; case DC_FAMILY_SUUNTO_VYPER2: case DC_FAMILY_SUUNTO_D9: - rc = suunto_d9_parser_create (&parser, context, device->devinfo.model, device->devinfo.serial); + rc = suunto_d9_parser_create (&parser, context, model, serial); break; case DC_FAMILY_SUUNTO_EONSTEEL: - rc = suunto_eonsteel_parser_create(&parser, context, device->devinfo.model); + rc = suunto_eonsteel_parser_create(&parser, context, model); break; case DC_FAMILY_UWATEC_ALADIN: case DC_FAMILY_UWATEC_MEMOMOUSE: - rc = uwatec_memomouse_parser_create (&parser, context, device->clock.devtime, device->clock.systime); + rc = uwatec_memomouse_parser_create (&parser, context, devtime, systime); break; case DC_FAMILY_UWATEC_SMART: case DC_FAMILY_UWATEC_MERIDIAN: - rc = uwatec_smart_parser_create (&parser, context, device->devinfo.model, device->clock.devtime, device->clock.systime); + rc = uwatec_smart_parser_create (&parser, context, model, devtime, systime); break; case DC_FAMILY_REEFNET_SENSUS: - rc = reefnet_sensus_parser_create (&parser, context, device->clock.devtime, device->clock.systime); + rc = reefnet_sensus_parser_create (&parser, context, devtime, systime); break; case DC_FAMILY_REEFNET_SENSUSPRO: - rc = reefnet_sensuspro_parser_create (&parser, context, device->clock.devtime, device->clock.systime); + rc = reefnet_sensuspro_parser_create (&parser, context, devtime, systime); break; case DC_FAMILY_REEFNET_SENSUSULTRA: - rc = reefnet_sensusultra_parser_create (&parser, context, device->clock.devtime, device->clock.systime); + rc = reefnet_sensusultra_parser_create (&parser, context, devtime, systime); break; case DC_FAMILY_OCEANIC_VTPRO: - rc = oceanic_vtpro_parser_create (&parser, context); + rc = oceanic_vtpro_parser_create2 (&parser, context, model); break; case DC_FAMILY_OCEANIC_VEO250: - rc = oceanic_veo250_parser_create (&parser, context, device->devinfo.model); + rc = oceanic_veo250_parser_create (&parser, context, model); break; case DC_FAMILY_OCEANIC_ATOM2: - if (device->devinfo.model == REACTPROWHITE) - rc = oceanic_veo250_parser_create (&parser, context, device->devinfo.model); + if (model == REACTPROWHITE) + rc = oceanic_veo250_parser_create (&parser, context, model); else - rc = oceanic_atom2_parser_create (&parser, context, device->devinfo.model, device->devinfo.serial); + rc = oceanic_atom2_parser_create (&parser, context, model, serial); break; case DC_FAMILY_MARES_NEMO: case DC_FAMILY_MARES_PUCK: - rc = mares_nemo_parser_create (&parser, context, device->devinfo.model); + rc = mares_nemo_parser_create (&parser, context, model); break; case DC_FAMILY_MARES_DARWIN: - rc = mares_darwin_parser_create (&parser, context, device->devinfo.model); + rc = mares_darwin_parser_create (&parser, context, model); break; case DC_FAMILY_MARES_ICONHD: - rc = mares_iconhd_parser_create (&parser, context, device->devinfo.model); + rc = mares_iconhd_parser_create (&parser, context, model); break; case DC_FAMILY_HW_OSTC: - rc = hw_ostc_parser_create (&parser, context, device->devinfo.serial, 0); + rc = hw_ostc_parser_create (&parser, context, serial, 0); break; case DC_FAMILY_HW_FROG: case DC_FAMILY_HW_OSTC3: - rc = hw_ostc_parser_create (&parser, context, device->devinfo.serial, 1); + rc = hw_ostc3_parser_create (&parser, context, serial, model); break; case DC_FAMILY_CRESSI_EDY: case DC_FAMILY_ZEAGLE_N2ITION3: - rc = cressi_edy_parser_create (&parser, context, device->devinfo.model); + rc = cressi_edy_parser_create (&parser, context, model); break; case DC_FAMILY_CRESSI_LEONARDO: rc = cressi_leonardo_parser_create (&parser, context); @@ -131,10 +129,10 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device) rc = atomics_cobalt_parser_create (&parser, context); break; case DC_FAMILY_SHEARWATER_PREDATOR: - rc = shearwater_predator_parser_create (&parser, context, device->devinfo.serial); + rc = shearwater_predator_parser_create (&parser, context, serial); break; case DC_FAMILY_SHEARWATER_PETREL: - rc = shearwater_petrel_parser_create (&parser, context, device->devinfo.serial); + rc = shearwater_petrel_parser_create (&parser, context, serial); break; case DC_FAMILY_DIVERITE_NITEKQ: rc = diverite_nitekq_parser_create (&parser, context); @@ -143,10 +141,10 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device) rc = citizen_aqualand_parser_create (&parser, context); break; case DC_FAMILY_DIVESYSTEM_IDIVE: - rc = divesystem_idive_parser_create2 (&parser, context, device->devinfo.model); + rc = divesystem_idive_parser_create2 (&parser, context, model); break; case DC_FAMILY_COCHRAN_COMMANDER: - rc = cochran_commander_parser_create (&parser, context, device->devinfo.model); + rc = cochran_commander_parser_create (&parser, context, model); break; default: return DC_STATUS_INVALIDARGS; @@ -157,6 +155,28 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device) return rc; } +dc_status_t +dc_parser_new (dc_parser_t **out, dc_device_t *device) +{ + if (device == NULL) + return DC_STATUS_INVALIDARGS; + + return dc_parser_new_internal (out, device->context, + dc_device_get_type (device), + device->devinfo.model, + device->devinfo.serial, + device->clock.devtime, device->clock.systime); +} + +dc_status_t +dc_parser_new2 (dc_parser_t **out, dc_context_t *context, dc_descriptor_t *descriptor, unsigned int devtime, dc_ticks_t systime) +{ + return dc_parser_new_internal (out, context, + dc_descriptor_get_type (descriptor), + dc_descriptor_get_model (descriptor), + dc_descriptor_get_serial (descriptor), + devtime, systime); +} dc_parser_t * dc_parser_allocate (dc_context_t *context, const dc_parser_vtable_t *vtable) diff --git a/src/reefnet_sensus.c b/src/reefnet_sensus.c index 0660155..51e9a7f 100644 --- a/src/reefnet_sensus.c +++ b/src/reefnet_sensus.c @@ -32,17 +32,12 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &reefnet_sensus_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define SZ_MEMORY 32768 #define SZ_HANDSHAKE 10 typedef struct reefnet_sensus_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; unsigned char handshake[SZ_HANDSHAKE]; unsigned int waiting; unsigned int timestamp; @@ -70,14 +65,15 @@ static const dc_device_vtable_t reefnet_sensus_device_vtable = { static dc_status_t reefnet_sensus_cancel (reefnet_sensus_device_t *device) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Send the command to the device. unsigned char command = 0x00; - int n = serial_write (device->port, &command, 1); - if (n != 1) { + status = dc_serial_write (device->port, &command, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // The device leaves the waiting state. @@ -112,37 +108,35 @@ reefnet_sensus_device_open (dc_device_t **out, dc_context_t *context, const char memset (device->handshake, 0, sizeof (device->handshake)); // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (19200 8N1). - rc = serial_configure (device->port, 19200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 19200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (3000 ms). - if (serial_set_timeout (device->port, 3000) == -1) { + status = dc_serial_set_timeout (device->port, 3000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Make sure everything is in a sane state. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -154,15 +148,18 @@ reefnet_sensus_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; reefnet_sensus_device_t *device = (reefnet_sensus_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Safely close the connection if the last handshake was // successful, but no data transfer was ever initiated. if (device->waiting) reefnet_sensus_cancel (device); + // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -208,22 +205,23 @@ reefnet_sensus_device_set_fingerprint (dc_device_t *abstract, const unsigned cha static dc_status_t reefnet_sensus_handshake (reefnet_sensus_device_t *device) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Send the command to the device. unsigned char command = 0x0A; - int n = serial_write (device->port, &command, 1); - if (n != 1) { + status = dc_serial_write (device->port, &command, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Receive the answer from the device. unsigned char handshake[SZ_HANDSHAKE + 2] = {0}; - n = serial_read (device->port, handshake, sizeof (handshake)); - if (n != sizeof (handshake)) { + status = dc_serial_read (device->port, handshake, sizeof (handshake), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the handshake."); - return EXITCODE (n); + return status; } // Verify the header of the packet. @@ -264,7 +262,7 @@ reefnet_sensus_handshake (reefnet_sensus_device_t *device) // Wait at least 10 ms to ensures the data line is // clear before transmission from the host begins. - serial_sleep (device->port, 10); + dc_serial_sleep (device->port, 10); return DC_STATUS_SUCCESS; } @@ -273,6 +271,7 @@ reefnet_sensus_handshake (reefnet_sensus_device_t *device) static dc_status_t reefnet_sensus_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) { + dc_status_t status = DC_STATUS_SUCCESS; reefnet_sensus_device_t *device = (reefnet_sensus_device_t*) abstract; // Erase the current contents of the buffer and @@ -294,10 +293,10 @@ reefnet_sensus_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Send the command to the device. unsigned char command = 0x40; - int n = serial_write (device->port, &command, 1); - if (n != 1) { + status = dc_serial_write (device->port, &command, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // The device leaves the waiting state. @@ -311,10 +310,10 @@ reefnet_sensus_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) if (len > 128) len = 128; - n = serial_read (device->port, answer + nbytes, len); - if (n != len) { + status = dc_serial_read (device->port, answer + nbytes, len, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Update and emit a progress event. diff --git a/src/reefnet_sensuspro.c b/src/reefnet_sensuspro.c index 8e17f1e..b9c08db 100644 --- a/src/reefnet_sensuspro.c +++ b/src/reefnet_sensuspro.c @@ -32,17 +32,12 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &reefnet_sensuspro_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define SZ_MEMORY 56320 #define SZ_HANDSHAKE 10 typedef struct reefnet_sensuspro_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; unsigned char handshake[SZ_HANDSHAKE]; unsigned int timestamp; unsigned int devtime; @@ -90,37 +85,35 @@ reefnet_sensuspro_device_open (dc_device_t **out, dc_context_t *context, const c memset (device->handshake, 0, sizeof (device->handshake)); // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (19200 8N1). - rc = serial_configure (device->port, 19200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 19200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (3000ms). - if (serial_set_timeout (device->port, 3000) == -1) { + status = dc_serial_set_timeout (device->port, 3000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Make sure everything is in a sane state. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -132,10 +125,12 @@ reefnet_sensuspro_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; reefnet_sensuspro_device_t *device = (reefnet_sensuspro_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -181,21 +176,22 @@ reefnet_sensuspro_device_set_fingerprint (dc_device_t *abstract, const unsigned static dc_status_t reefnet_sensuspro_handshake (reefnet_sensuspro_device_t *device) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Assert a break condition. - serial_set_break (device->port, 1); + dc_serial_set_break (device->port, 1); // Receive the handshake from the dive computer. unsigned char handshake[SZ_HANDSHAKE + 2] = {0}; - int rc = serial_read (device->port, handshake, sizeof (handshake)); - if (rc != sizeof (handshake)) { + status = dc_serial_read (device->port, handshake, sizeof (handshake), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the handshake."); - return EXITCODE (rc); + return status; } // Clear the break condition again. - serial_set_break (device->port, 0); + dc_serial_set_break (device->port, 0); // Verify the checksum of the handshake packet. unsigned short crc = array_uint16_le (handshake + SZ_HANDSHAKE); @@ -231,7 +227,7 @@ reefnet_sensuspro_handshake (reefnet_sensuspro_device_t *device) vendor.size = sizeof (device->handshake); device_event_emit (abstract, DC_EVENT_VENDOR, &vendor); - serial_sleep (device->port, 10); + dc_serial_sleep (device->port, 10); return DC_STATUS_SUCCESS; } @@ -240,6 +236,7 @@ reefnet_sensuspro_handshake (reefnet_sensuspro_device_t *device) static dc_status_t reefnet_sensuspro_send (reefnet_sensuspro_device_t *device, unsigned char command) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Wake-up the device. @@ -248,10 +245,10 @@ reefnet_sensuspro_send (reefnet_sensuspro_device_t *device, unsigned char comman return rc; // Send the instruction code to the device. - int n = serial_write (device->port, &command, 1); - if (n != 1) { + status = dc_serial_write (device->port, &command, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } return DC_STATUS_SUCCESS; @@ -261,6 +258,7 @@ reefnet_sensuspro_send (reefnet_sensuspro_device_t *device, unsigned char comman static dc_status_t reefnet_sensuspro_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) { + dc_status_t status = DC_STATUS_SUCCESS; reefnet_sensuspro_device_t *device = (reefnet_sensuspro_device_t*) abstract; // Erase the current contents of the buffer and @@ -287,10 +285,10 @@ reefnet_sensuspro_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) if (len > 256) len = 256; - int n = serial_read (device->port, answer + nbytes, len); - if (n != len) { + status = dc_serial_read (device->port, answer + nbytes, len, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Update and emit a progress event. @@ -338,6 +336,7 @@ reefnet_sensuspro_device_foreach (dc_device_t *abstract, dc_dive_callback_t call dc_status_t reefnet_sensuspro_device_write_interval (dc_device_t *abstract, unsigned char interval) { + dc_status_t status = DC_STATUS_SUCCESS; reefnet_sensuspro_device_t *device = (reefnet_sensuspro_device_t*) abstract; if (!ISINSTANCE (abstract)) @@ -351,12 +350,12 @@ reefnet_sensuspro_device_write_interval (dc_device_t *abstract, unsigned char in if (rc != DC_STATUS_SUCCESS) return rc; - serial_sleep (device->port, 10); + dc_serial_sleep (device->port, 10); - int n = serial_write (device->port, &interval, 1); - if (n != 1) { + status = dc_serial_write (device->port, &interval, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the data packet."); - return EXITCODE (n); + return status; } return DC_STATUS_SUCCESS; diff --git a/src/reefnet_sensusultra.c b/src/reefnet_sensusultra.c index db070e6..ead2388 100644 --- a/src/reefnet_sensusultra.c +++ b/src/reefnet_sensusultra.c @@ -33,11 +33,6 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &reefnet_sensusultra_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define SZ_PACKET 512 #define SZ_MEMORY 2080768 #define SZ_USER 16384 @@ -51,7 +46,7 @@ typedef struct reefnet_sensusultra_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; unsigned char handshake[SZ_HANDSHAKE]; unsigned int timestamp; unsigned int devtime; @@ -99,37 +94,35 @@ reefnet_sensusultra_device_open (dc_device_t **out, dc_context_t *context, const memset (device->handshake, 0, sizeof (device->handshake)); // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (115200 8N1). - rc = serial_configure (device->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (3000ms). - if (serial_set_timeout (device->port, 3000) == -1) { + status = dc_serial_set_timeout (device->port, 3000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Make sure everything is in a sane state. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -141,10 +134,12 @@ reefnet_sensusultra_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; reefnet_sensusultra_device_t *device = (reefnet_sensusultra_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -190,14 +185,15 @@ reefnet_sensusultra_device_set_fingerprint (dc_device_t *abstract, const unsigne static dc_status_t reefnet_sensusultra_send_uchar (reefnet_sensusultra_device_t *device, unsigned char value) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Wait for the prompt byte. unsigned char prompt = 0; - int rc = serial_read (device->port, &prompt, 1); - if (rc != 1) { + status = dc_serial_read (device->port, &prompt, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the prompt byte"); - return EXITCODE (rc); + return status; } // Verify the prompt byte. @@ -207,10 +203,10 @@ reefnet_sensusultra_send_uchar (reefnet_sensusultra_device_t *device, unsigned c } // Send the value to the device. - rc = serial_write (device->port, &value, 1); - if (rc != 1) { + status = dc_serial_write (device->port, &value, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the value."); - return EXITCODE (rc); + return status; } return DC_STATUS_SUCCESS; @@ -239,18 +235,19 @@ reefnet_sensusultra_send_ushort (reefnet_sensusultra_device_t *device, unsigned static dc_status_t reefnet_sensusultra_packet (reefnet_sensusultra_device_t *device, unsigned char *data, unsigned int size, unsigned int header) { - assert (size >= header + 2); - + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; + assert (size >= header + 2); + if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; // Receive the data packet. - int rc = serial_read (device->port, data, size); - if (rc != size) { + status = dc_serial_read (device->port, data, size, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet."); - return EXITCODE (rc); + return status; } // Verify the checksum of the packet. @@ -349,7 +346,7 @@ static dc_status_t reefnet_sensusultra_send (reefnet_sensusultra_device_t *device, unsigned short command) { // Flush the input and output buffers. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); // Wake-up the device and send the instruction code. unsigned int nretries = 0; @@ -369,8 +366,8 @@ reefnet_sensusultra_send (reefnet_sensusultra_device_t *device, unsigned short c // not accidentally buffered by the host and (mis)interpreted as part // of the next packet. - serial_sleep (device->port, 250); - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_sleep (device->port, 250); + dc_serial_purge (device->port, DC_DIRECTION_ALL); } return DC_STATUS_SUCCESS; diff --git a/src/serial.h b/src/serial.h index 56d20c0..ac94ec8 100644 --- a/src/serial.h +++ b/src/serial.h @@ -19,101 +19,303 @@ * MA 02110-1301 USA */ -#ifndef SERIAL_H -#define SERIAL_H +#ifndef DC_SERIAL_H +#define DC_SERIAL_H +#include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -#include +/** + * Opaque object representing a serial connection. + */ +typedef struct dc_serial_t dc_serial_t; -typedef enum serial_parity_t { - SERIAL_PARITY_NONE, - SERIAL_PARITY_EVEN, - SERIAL_PARITY_ODD -} serial_parity_t; +/** + * The parity checking scheme. + */ +typedef enum dc_parity_t { + DC_PARITY_NONE, /**< No parity */ + DC_PARITY_ODD, /**< Odd parity */ + DC_PARITY_EVEN, /**< Even parity */ + DC_PARITY_MARK, /**< Mark parity (always 1) */ + DC_PARITY_SPACE /**< Space parity (alwasy 0) */ +} dc_parity_t; -typedef enum serial_flowcontrol_t { - SERIAL_FLOWCONTROL_NONE, - SERIAL_FLOWCONTROL_HARDWARE, - SERIAL_FLOWCONTROL_SOFTWARE -} serial_flowcontrol_t; +/** + * The number of stop bits. + */ +typedef enum dc_stopbits_t { + DC_STOPBITS_ONE, /**< 1 stop bit */ + DC_STOPBITS_ONEPOINTFIVE, /**< 1.5 stop bits*/ + DC_STOPBITS_TWO /**< 2 stop bits */ +} dc_stopbits_t; -typedef enum serial_queue_t { - SERIAL_QUEUE_INPUT = 0x01, - SERIAL_QUEUE_OUTPUT = 0x02, - SERIAL_QUEUE_BOTH = SERIAL_QUEUE_INPUT | SERIAL_QUEUE_OUTPUT -} serial_queue_t; +/** + * The flow control. + */ +typedef enum dc_flowcontrol_t { + DC_FLOWCONTROL_NONE, /**< No flow control */ + DC_FLOWCONTROL_HARDWARE, /**< Hardware (RTS/CTS) flow control */ + DC_FLOWCONTROL_SOFTWARE /**< Software (XON/XOFF) flow control */ +} dc_flowcontrol_t; -typedef enum serial_line_t { - SERIAL_LINE_DCD, // Data carrier detect - SERIAL_LINE_CTS, // Clear to send - SERIAL_LINE_DSR, // Data set ready - SERIAL_LINE_RNG, // Ring indicator -} serial_line_t; +/** + * The direction of the data transmission. + */ +typedef enum dc_direction_t { + DC_DIRECTION_INPUT = 0x01, /**< Input direction */ + DC_DIRECTION_OUTPUT = 0x02, /**< Output direction */ + DC_DIRECTION_ALL = DC_DIRECTION_INPUT | DC_DIRECTION_OUTPUT /**< All directions */ +} dc_direction_t; -typedef void (*serial_callback_t) (const char *name, void *userdata); +/** + * The serial line signals. + */ +typedef enum dc_line_t { + DC_LINE_DCD = 0x01, /**< Data carrier detect */ + DC_LINE_CTS = 0x02, /**< Clear to send */ + DC_LINE_DSR = 0x04, /**< Data set ready */ + DC_LINE_RNG = 0x08, /**< Ring indicator */ +} dc_line_t; -int serial_enumerate (serial_callback_t callback, void *userdata); +/** + * Serial enumeration callback. + * + * @param[in] name The name of the device node. + * @param[in] userdata The user data pointer. + */ +typedef void (*dc_serial_callback_t) (const char *name, void *userdata); -int serial_open (serial_t **device, dc_context_t *context, const char* name); +/** + * Enumerate the serial ports. + * + * @param[in] callback The callback function to call. + * @param[in] userdata User data to pass to the callback function. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_enumerate (dc_serial_callback_t callback, void *userdata); -int serial_close (serial_t *device); +/** + * Open a serial connection. + * + * @param[out] serial A location to store the serial connection. + * @param[in] context A valid context object. + * @param[in] name The name of the device node. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_open (dc_serial_t **serial, dc_context_t *context, const char *name); -int serial_configure (serial_t *device, int baudrate, int databits, int parity, int stopbits, int flowcontrol); +/** + * Close the serial connection and free all resources. + * + * @param[in] serial A valid serial connection. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_close (dc_serial_t *serial); -// -// Available read modes: -// -// * Blocking (timeout < 0): -// -// The read function is blocked until all the requested bytes have -// been received. If the requested number of bytes does not arrive, -// the function will block forever. -// -// * Non-blocking (timeout == 0): -// -// The read function returns immediately with the bytes that have already -// been received, even if no bytes have been received. -// -// * Timeout (timeout > 0): -// -// The read function is blocked until all the requested bytes have -// been received. If the requested number of bytes does not arrive -// within the specified amount of time, the function will return -// with the bytes that have already been received. -// +/** + * Configure the serial line settings of the connection. + * + * @param[in] serial A valid serial connection. + * @param[in] baudrate The baud rate setting. + * @param[in] databits The number of data bits. + * @param[in] parity The parity setting. + * @param[in] stopbits The number of stop bits. + * @param[in] flowcontrol The flow control setting. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_configure (dc_serial_t *serial, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol); -int serial_set_timeout (serial_t *device, long timeout /* milliseconds */); +/** + * Set the read timeout. + * + * There are three distinct modes available: + * + * 1. Blocking (timeout < 0): + * + * The read operation is blocked until all the requested bytes have + * been received. If the requested number of bytes does not arrive, + * the operation will block forever. + * + * 2. Non-blocking (timeout == 0): + * + * The read operation returns immediately with the bytes that have + * already been received, even if no bytes have been received. + * + * 3. Timeout (timeout > 0): + * + * The read operation is blocked until all the requested bytes have + * been received. If the requested number of bytes does not arrive + * within the specified amount of time, the operation will return + * with the bytes that have already been received. + * + * @param[in] serial A valid serial connection. + * @param[in] timeout The timeout in milliseconds. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_set_timeout (dc_serial_t *serial, int timeout); -int serial_set_queue_size (serial_t *device, unsigned int input, unsigned int output); +/** + * Set the state of the half duplex emulation. + * + * @param[in] serial A valid serial connection. + * @param[in] value The half duplex state. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_set_halfduplex (dc_serial_t *serial, unsigned int value); -int serial_set_halfduplex (serial_t *device, int value); +/** + * Set the receive latency. + * + * The effect of this setting is highly platform and driver specific. On + * Windows it does nothing at all, on Linux it controls the low latency + * flag (e.g. only zero vs non-zero latency), and on Mac OS X it sets + * the receive latency as requested. + * + * @param[in] serial A valid serial connection. + * @param[in] value The latency in milliseconds. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_set_latency (dc_serial_t *serial, unsigned int value); -int serial_set_latency (serial_t *device, unsigned int milliseconds); +/** + * Read data from the serial connection. + * + * @param[in] serial A valid serial connection. + * @param[out] data The memory buffer to read the data into. + * @param[in] size The number of bytes to read. + * @param[out] actual An (optional) location to store the actual + * number of bytes transferred. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_read (dc_serial_t *serial, void *data, size_t size, size_t *actual); -int serial_read (serial_t *device, void* data, unsigned int size); -int serial_write (serial_t *device, const void* data, unsigned int size); +/** + * Write data to the serial connection. + * + * @param[in] serial A valid serial connection. + * @param[in] data The memory buffer to write the data from. + * @param[in] size The number of bytes to write. + * @param[out] actual An (optional) location to store the actual + * number of bytes transferred. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_write (dc_serial_t *serial, const void *data, size_t size, size_t *actual); -int serial_flush (serial_t *device, int queue); +/** + * Flush the internal output buffer and wait until the data has been + * transmitted. + * + * @param[in] serial A valid serial connection. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_flush (dc_serial_t *serial); -int serial_send_break (serial_t *device); +/** + * Discards all data from the internal buffers. + * + * @param[in] serial A valid serial connection. + * @param[in] direction The direction of the buffer(s). + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_purge (dc_serial_t *serial, dc_direction_t direction); -int serial_set_break (serial_t *device, int level); -int serial_set_dtr (serial_t *device, int level); -int serial_set_rts (serial_t *device, int level); +/** + * Set the state of the break condition. + * + * @param[in] serial A valid serial connection. + * @param[in] value The break condition state. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_set_break (dc_serial_t *serial, unsigned int value); -int serial_get_received (serial_t *device); -int serial_get_transmitted (serial_t *device); +/** + * Set the state of the DTR line. + * + * @param[in] serial A valid serial connection. + * @param[in] value The DTR line state. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_set_dtr (dc_serial_t *serial, unsigned int value); -int serial_get_line (serial_t *device, int line); +/** + * Set the state of the RTS line. + * + * @param[in] serial A valid serial connection. + * @param[in] value The RTS line state. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_set_rts (dc_serial_t *serial, unsigned int value); -int serial_sleep (serial_t *device, unsigned long timeout /* milliseconds */); +/** + * Query the number of available bytes in the input buffer. + * + * @param[in] serial A valid serial connection. + * @param[out] value A location to store the number of bytes in the + * input buffer. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_get_available (dc_serial_t *serial, size_t *value); + +/** + * Query the state of the line signals. + * + * @param[in] serial A valid serial connection. + * @param[out] value A location to store the bitmap with the state of + * the line signals. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_get_lines (dc_serial_t *serial, unsigned int *value); + +/** + * Suspend execution of the current thread for the specified amount of + * time. + * + * @param[in] serial A valid serial connection. + * @param[in] milliseconds The number of milliseconds to sleep. + * @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code + * on failure. + */ +dc_status_t +dc_serial_sleep (dc_serial_t *serial, unsigned int milliseconds); #ifdef __cplusplus } #endif /* __cplusplus */ -#endif /* SERIAL_H */ +#endif /* DC_SERIAL_H */ diff --git a/src/serial_posix.c b/src/serial_posix.c index 7cc83b6..5a84757 100644 --- a/src/serial_posix.c +++ b/src/serial_posix.c @@ -54,16 +54,17 @@ #endif #include "serial.h" +#include "common-private.h" #include "context-private.h" -struct serial_t { +struct dc_serial_t { /* Library context. */ dc_context_t *context; /* * The file descriptor corresponding to the serial port. */ int fd; - long timeout; + int timeout; /* * Serial port settings are saved into this variable immediately * after the port is opened. These settings are restored when the @@ -76,9 +77,26 @@ struct serial_t { unsigned int nbits; }; +static dc_status_t +syserror(int errcode) +{ + switch (errcode) { + case EINVAL: + return DC_STATUS_INVALIDARGS; + case ENOMEM: + return DC_STATUS_NOMEMORY; + case ENOENT: + return DC_STATUS_NODEVICE; + case EACCES: + case EBUSY: + return DC_STATUS_NOACCESS; + default: + return DC_STATUS_IO; + } +} -int -serial_enumerate (serial_callback_t callback, void *userdata) +dc_status_t +dc_serial_enumerate (dc_serial_callback_t callback, void *userdata) { DIR *dp = NULL; struct dirent *ep = NULL; @@ -97,7 +115,7 @@ serial_enumerate (serial_callback_t callback, void *userdata) dp = opendir (dirname); if (dp == NULL) { - return -1; + return DC_STATUS_IO; } while ((ep = readdir (dp)) != NULL) { @@ -107,7 +125,7 @@ serial_enumerate (serial_callback_t callback, void *userdata) int n = snprintf (filename, sizeof (filename), "%s/%s", dirname, ep->d_name); if (n >= sizeof (filename)) { closedir (dp); - return -1; + return DC_STATUS_NOMEMORY; } callback (filename, userdata); @@ -118,27 +136,24 @@ serial_enumerate (serial_callback_t callback, void *userdata) closedir (dp); - return 0; + return DC_STATUS_SUCCESS; } - -// -// Open the serial port. -// - -int -serial_open (serial_t **out, dc_context_t *context, const char* name) +dc_status_t +dc_serial_open (dc_serial_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + if (out == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; INFO (context, "Open: name=%s", name ? name : ""); // Allocate memory. - serial_t *device = (serial_t *) malloc (sizeof (serial_t)); + dc_serial_t *device = (dc_serial_t *) malloc (sizeof (dc_serial_t)); if (device == NULL) { SYSERROR (context, ENOMEM); - return -1; // ENOMEM (Not enough space) + return DC_STATUS_NOMEMORY; } // Library context. @@ -156,14 +171,18 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) // without waiting for the modem connection to complete. device->fd = open (name, O_RDWR | O_NOCTTY | O_NONBLOCK); if (device->fd == -1) { - SYSERROR (context, errno); + int errcode = errno; + SYSERROR (context, errcode); + status = syserror (errcode); goto error_free; } #ifndef ENABLE_PTY // Enable exclusive access mode. if (ioctl (device->fd, TIOCEXCL, NULL) != 0) { - SYSERROR (context, errno); + int errcode = errno; + SYSERROR (context, errcode); + status = syserror (errcode); goto error_close; } #endif @@ -173,37 +192,36 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) // It is also used to check if the obtained // file descriptor represents a terminal device. if (tcgetattr (device->fd, &device->tty) != 0) { - SYSERROR (context, errno); + int errcode = errno; + SYSERROR (context, errcode); + status = syserror (errcode); goto error_close; } *out = device; - return 0; + return DC_STATUS_SUCCESS; error_close: close (device->fd); error_free: free (device); - return -1; + return status; } -// -// Close the serial port. -// - -int -serial_close (serial_t *device) +dc_status_t +dc_serial_close (dc_serial_t *device) { - int errcode = 0; + dc_status_t status = DC_STATUS_SUCCESS; if (device == NULL) - return 0; + return DC_STATUS_SUCCESS; // Restore the initial terminal attributes. if (tcsetattr (device->fd, TCSANOW, &device->tty) != 0) { - SYSERROR (device->context, errno); - errcode = -1; + int errcode = errno; + SYSERROR (device->context, errcode); + dc_status_set_error(&status, syserror (errcode)); } #ifndef ENABLE_PTY @@ -213,25 +231,22 @@ serial_close (serial_t *device) // Close the device. if (close (device->fd) != 0) { - SYSERROR (device->context, errno); - errcode = -1; + int errcode = errno; + SYSERROR (device->context, errcode); + dc_status_set_error(&status, syserror (errcode)); } // Free memory. free (device); - return errcode; + return status; } -// -// Configure the serial port (baudrate, databits, parity, stopbits and flowcontrol). -// - -int -serial_configure (serial_t *device, int baudrate, int databits, int parity, int stopbits, int flowcontrol) +dc_status_t +dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol) { if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; INFO (device->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i", baudrate, databits, parity, stopbits, flowcontrol); @@ -240,8 +255,9 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int struct termios tty; memset (&tty, 0, sizeof (tty)); if (tcgetattr (device->fd, &tty) != 0) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + return syserror (errcode); } // Setup raw input/output mode without echo. @@ -336,8 +352,9 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int } if (cfsetispeed (&tty, baud) != 0 || cfsetospeed (&tty, baud) != 0) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + return syserror (errcode); } // Set the character size. @@ -356,71 +373,86 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int tty.c_cflag |= CS8; break; default: - return -1; + return DC_STATUS_INVALIDARGS; } // Set the parity type. +#ifdef CMSPAR + tty.c_cflag &= ~(PARENB | PARODD | CMSPAR); +#else tty.c_cflag &= ~(PARENB | PARODD); +#endif tty.c_iflag &= ~(IGNPAR | PARMRK | INPCK); switch (parity) { - case SERIAL_PARITY_NONE: // No parity + case DC_PARITY_NONE: tty.c_iflag |= IGNPAR; break; - case SERIAL_PARITY_EVEN: // Even parity + case DC_PARITY_EVEN: tty.c_cflag |= PARENB; tty.c_iflag |= INPCK; break; - case SERIAL_PARITY_ODD: // Odd parity + case DC_PARITY_ODD: tty.c_cflag |= (PARENB | PARODD); tty.c_iflag |= INPCK; break; +#ifdef CMSPAR + case DC_PARITY_MARK: + tty.c_cflag |= (PARENB | PARODD | CMSPAR); + tty.c_iflag |= INPCK; + break; + case DC_PARITY_SPACE: + tty.c_cflag |= (PARENB | CMSPAR); + tty.c_iflag |= INPCK; + break; +#endif default: - return -1; + return DC_STATUS_INVALIDARGS; } // Set the number of stop bits. switch (stopbits) { - case 1: // One stopbit + case DC_STOPBITS_ONE: tty.c_cflag &= ~CSTOPB; break; - case 2: // Two stopbits + case DC_STOPBITS_TWO: tty.c_cflag |= CSTOPB; break; default: - return -1; + return DC_STATUS_INVALIDARGS; } // Set the flow control. switch (flowcontrol) { - case SERIAL_FLOWCONTROL_NONE: // No flow control. + case DC_FLOWCONTROL_NONE: #ifdef CRTSCTS tty.c_cflag &= ~CRTSCTS; #endif tty.c_iflag &= ~(IXON | IXOFF | IXANY); break; - case SERIAL_FLOWCONTROL_HARDWARE: // Hardware (RTS/CTS) flow control. + case DC_FLOWCONTROL_HARDWARE: #ifdef CRTSCTS tty.c_cflag |= CRTSCTS; tty.c_iflag &= ~(IXON | IXOFF | IXANY); break; #else - return -1; // Hardware flow control is unsupported. + return DC_STATUS_UNSUPPORTED; #endif - case SERIAL_FLOWCONTROL_SOFTWARE: // Software (XON/XOFF) flow control. + case DC_FLOWCONTROL_SOFTWARE: #ifdef CRTSCTS tty.c_cflag &= ~CRTSCTS; #endif tty.c_iflag |= (IXON | IXOFF); break; default: - return -1; + return DC_STATUS_INVALIDARGS; } // Apply the new settings. if (tcsetattr (device->fd, TCSANOW, &tty) != 0 && NOPTY) { #if 0 // who cares - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + return syserror (errcode); #endif } @@ -430,8 +462,9 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int // Get the current settings. struct serial_struct ss; if (ioctl (device->fd, TIOCGSERIAL, &ss) != 0 && NOPTY) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + return syserror (errcode); } // Set the custom divisor. @@ -441,82 +474,66 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int // Apply the new settings. if (ioctl (device->fd, TIOCSSERIAL, &ss) != 0 && NOPTY) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + return syserror (errcode); } #elif defined(IOSSIOSPEED) speed_t speed = baudrate; if (ioctl (device->fd, IOSSIOSPEED, &speed) != 0 && NOPTY) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + return syserror (errcode); } #else // Custom baudrates are not supported. - return -1; + return DC_STATUS_UNSUPPORTED; #endif } device->baudrate = baudrate; device->nbits = 1 + databits + stopbits + (parity ? 1 : 0); - return 0; + return DC_STATUS_SUCCESS; } -// -// Configure the serial port (timeouts). -// - -int -serial_set_timeout (serial_t *device, long timeout) +dc_status_t +dc_serial_set_timeout (dc_serial_t *device, int timeout) { if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; - INFO (device->context, "Timeout: value=%li", timeout); + INFO (device->context, "Timeout: value=%i", timeout); device->timeout = timeout; - return 0; + return DC_STATUS_SUCCESS; } - -// -// Configure the serial port (recommended size of the input/output buffers). -// - -int -serial_set_queue_size (serial_t *device, unsigned int input, unsigned int output) +dc_status_t +dc_serial_set_halfduplex (dc_serial_t *device, unsigned int value) { if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) - - return 0; -} - - -int -serial_set_halfduplex (serial_t *device, int value) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; device->halfduplex = value; - return 0; + return DC_STATUS_SUCCESS; } -int -serial_set_latency (serial_t *device, unsigned int milliseconds) +dc_status_t +dc_serial_set_latency (dc_serial_t *device, unsigned int milliseconds) { if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; #if defined(TIOCGSERIAL) && defined(TIOCSSERIAL) && !defined(__ANDROID__) // Get the current settings. struct serial_struct ss; if (ioctl (device->fd, TIOCGSERIAL, &ss) != 0 && NOPTY) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + return syserror (errcode); } // Set or clear the low latency flag. @@ -528,8 +545,9 @@ serial_set_latency (serial_t *device, unsigned int milliseconds) // Apply the new settings. if (ioctl (device->fd, TIOCSSERIAL, &ss) != 0 && NOPTY) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + return syserror (errcode); } #elif defined(IOSSDATALAT) // Set the receive latency in microseconds. Serial drivers use this @@ -537,28 +555,33 @@ serial_set_latency (serial_t *device, unsigned int milliseconds) // the hardware. A value of zero restores the default value. unsigned long usec = (milliseconds == 0 ? 1 : milliseconds * 1000); if (ioctl (device->fd, IOSSDATALAT, &usec) != 0 && NOPTY) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + return syserror (errcode); } #endif - return 0; + return DC_STATUS_SUCCESS; } -int -serial_read (serial_t *device, void *data, unsigned int size) +dc_status_t +dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual) { - if (device == NULL) - return -1; // EINVAL (Invalid argument) + dc_status_t status = DC_STATUS_SUCCESS; + size_t nbytes = 0; + + if (device == NULL) { + status = DC_STATUS_INVALIDARGS; + goto out; + } // The total timeout. - long timeout = device->timeout; + int timeout = device->timeout; // The absolute target time. struct timeval tve; int init = 1; - unsigned int nbytes = 0; while (nbytes < size) { fd_set fds; FD_ZERO (&fds); @@ -568,8 +591,10 @@ serial_read (serial_t *device, void *data, unsigned int size) if (timeout > 0) { struct timeval now; if (gettimeofday (&now, NULL) != 0) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + status = syserror (errcode); + goto out; } if (init) { @@ -592,20 +617,24 @@ serial_read (serial_t *device, void *data, unsigned int size) int rc = select (device->fd + 1, &fds, NULL, NULL, timeout >= 0 ? &tvt : NULL); if (rc < 0) { - if (errno == EINTR) + int errcode = errno; + if (errcode == EINTR) continue; // Retry. - SYSERROR (device->context, errno); - return -1; // Error during select call. + SYSERROR (device->context, errcode); + status = syserror (errcode); + goto out; } else if (rc == 0) { break; // Timeout. } - int n = read (device->fd, (char *) data + nbytes, size - nbytes); + ssize_t n = read (device->fd, (char *) data + nbytes, size - nbytes); if (n < 0) { - if (errno == EINTR || errno == EAGAIN) + int errcode = errno; + if (errcode == EINTR || errcode == EAGAIN) continue; // Retry. - SYSERROR (device->context, errno); - return -1; // Error during read call. + SYSERROR (device->context, errcode); + status = syserror (errcode); + goto out; } else if (n == 0) { break; // EOF. } @@ -613,28 +642,41 @@ serial_read (serial_t *device, void *data, unsigned int size) nbytes += n; } + if (nbytes != size) { + status = DC_STATUS_TIMEOUT; + } + +out: HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes); - return nbytes; + if (actual) + *actual = nbytes; + + return status; } - -int -serial_write (serial_t *device, const void *data, unsigned int size) +dc_status_t +dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *actual) { - if (device == NULL) - return -1; // EINVAL (Invalid argument) + dc_status_t status = DC_STATUS_SUCCESS; + size_t nbytes = 0; + + if (device == NULL) { + status = DC_STATUS_INVALIDARGS; + goto out; + } struct timeval tve, tvb; if (device->halfduplex) { // Get the current time. if (gettimeofday (&tvb, NULL) != 0) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + status = syserror (errcode); + goto out; } } - unsigned int nbytes = 0; while (nbytes < size) { fd_set fds; FD_ZERO (&fds); @@ -642,20 +684,24 @@ serial_write (serial_t *device, const void *data, unsigned int size) int rc = select (device->fd + 1, NULL, &fds, NULL, NULL); if (rc < 0) { - if (errno == EINTR) + int errcode = errno; + if (errcode == EINTR) continue; // Retry. - SYSERROR (device->context, errno); - return -1; // Error during select call. + SYSERROR (device->context, errcode); + status = syserror (errcode); + goto out; } else if (rc == 0) { break; // Timeout. } - int n = write (device->fd, (char *) data + nbytes, size - nbytes); + ssize_t n = write (device->fd, (const char *) data + nbytes, size - nbytes); if (n < 0) { - if (errno == EINTR || errno == EAGAIN) + int errcode = errno; + if (errcode == EINTR || errcode == EAGAIN) continue; // Retry. - SYSERROR (device->context, errno); - return -1; // Error during write call. + SYSERROR (device->context, errcode); + status = syserror (errcode); + goto out; } else if (n == 0) { break; // EOF. } @@ -670,17 +716,21 @@ serial_write (serial_t *device, const void *data, unsigned int size) #else while (tcdrain (device->fd) != 0) { #endif - if (errno != EINTR ) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + if (errcode != EINTR ) { + SYSERROR (device->context, errcode); + status = syserror (errcode); + goto out; } } if (device->halfduplex) { // Get the current time. if (gettimeofday (&tve, NULL) != 0) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + status = syserror (errcode); + goto out; } // Calculate the elapsed time (microseconds). @@ -699,88 +749,87 @@ serial_write (serial_t *device, const void *data, unsigned int size) // The remaining time is rounded up to the nearest millisecond to // match the Windows implementation. The higher resolution is // pointless anyway, since we already added a fudge factor above. - serial_sleep (device, (remaining + 999) / 1000); + dc_serial_sleep (device, (remaining + 999) / 1000); } } +out: HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes); - return nbytes; + if (actual) + *actual = nbytes; + + return status; } - -int -serial_flush (serial_t *device, int queue) +dc_status_t +dc_serial_purge (dc_serial_t *device, dc_direction_t direction) { if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; - INFO (device->context, "Flush: queue=%u, input=%i, output=%i", queue, - serial_get_received (device), - serial_get_transmitted (device)); + INFO (device->context, "Purge: direction=%u", direction); int flags = 0; - switch (queue) { - case SERIAL_QUEUE_INPUT: + switch (direction) { + case DC_DIRECTION_INPUT: flags = TCIFLUSH; break; - case SERIAL_QUEUE_OUTPUT: + case DC_DIRECTION_OUTPUT: flags = TCOFLUSH; break; - default: + case DC_DIRECTION_ALL: flags = TCIOFLUSH; break; + default: + return DC_STATUS_INVALIDARGS; } if (tcflush (device->fd, flags) != 0) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + return syserror (errcode); } - return 0; + return DC_STATUS_SUCCESS; } - -int -serial_send_break (serial_t *device) +dc_status_t +dc_serial_flush (dc_serial_t *device) { if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; - if (tcsendbreak (device->fd, 0) != 0) { - SYSERROR (device->context, errno); - return -1; - } - - return 0; + INFO (device->context, "Flush: none"); + + return DC_STATUS_SUCCESS; } - -int -serial_set_break (serial_t *device, int level) +dc_status_t +dc_serial_set_break (dc_serial_t *device, unsigned int level) { if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; INFO (device->context, "Break: value=%i", level); unsigned long action = (level ? TIOCSBRK : TIOCCBRK); if (ioctl (device->fd, action, NULL) != 0 && NOPTY) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + return syserror (errcode); } - return 0; + return DC_STATUS_SUCCESS; } - -int -serial_set_dtr (serial_t *device, int level) +dc_status_t +dc_serial_set_dtr (dc_serial_t *device, unsigned int level) { if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; INFO (device->context, "DTR: value=%i", level); @@ -788,19 +837,19 @@ serial_set_dtr (serial_t *device, int level) int value = TIOCM_DTR; if (ioctl (device->fd, action, &value) != 0 && NOPTY) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + return syserror (errcode); } - return 0; + return DC_STATUS_SUCCESS; } - -int -serial_set_rts (serial_t *device, int level) +dc_status_t +dc_serial_set_rts (dc_serial_t *device, unsigned int level) { if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; INFO (device->context, "RTS: value=%i", level); @@ -808,93 +857,82 @@ serial_set_rts (serial_t *device, int level) int value = TIOCM_RTS; if (ioctl (device->fd, action, &value) != 0 && NOPTY) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + return syserror (errcode); } - return 0; + return DC_STATUS_SUCCESS; } - -int -serial_get_received (serial_t *device) +dc_status_t +dc_serial_get_available (dc_serial_t *device, size_t *value) { if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; int bytes = 0; if (ioctl (device->fd, TIOCINQ, &bytes) != 0) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + return syserror (errcode); } - return bytes; + if (value) + *value = bytes; + + return DC_STATUS_SUCCESS; } - -int -serial_get_transmitted (serial_t *device) +dc_status_t +dc_serial_get_lines (dc_serial_t *device, unsigned int *value) { + unsigned int lines = 0; + if (device == NULL) - return -1; // EINVAL (Invalid argument) - - int bytes = 0; - if (ioctl (device->fd, TIOCOUTQ, &bytes) != 0) { - SYSERROR (device->context, errno); - return -1; - } - - return bytes; -} - - -int -serial_get_line (serial_t *device, int line) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; int status = 0; if (ioctl (device->fd, TIOCMGET, &status) != 0) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + SYSERROR (device->context, errcode); + return syserror (errcode); } - switch (line) { - case SERIAL_LINE_DCD: - return (status & TIOCM_CAR) == TIOCM_CAR; - case SERIAL_LINE_CTS: - return (status & TIOCM_CTS) == TIOCM_CTS; - case SERIAL_LINE_DSR: - return (status & TIOCM_DSR) == TIOCM_DSR; - case SERIAL_LINE_RNG: - return (status & TIOCM_RNG) == TIOCM_RNG; - default: - return -1; - } + if (status & TIOCM_CAR) + lines |= DC_LINE_DCD; + if (status & TIOCM_CTS) + lines |= DC_LINE_CTS; + if (status & TIOCM_DSR) + lines |= DC_LINE_DSR; + if (status & TIOCM_RNG) + lines |= DC_LINE_RNG; - return 0; + if (value) + *value = lines; + + return DC_STATUS_SUCCESS; } - -int -serial_sleep (serial_t *device, unsigned long timeout) +dc_status_t +dc_serial_sleep (dc_serial_t *device, unsigned int timeout) { if (device == NULL) - return -1; + return DC_STATUS_INVALIDARGS; - INFO (device->context, "Sleep: value=%lu", timeout); + INFO (device->context, "Sleep: value=%u", timeout); struct timespec ts; ts.tv_sec = (timeout / 1000); ts.tv_nsec = (timeout % 1000) * 1000000; while (nanosleep (&ts, &ts) != 0) { - if (errno != EINTR ) { - SYSERROR (device->context, errno); - return -1; + int errcode = errno; + if (errcode != EINTR ) { + SYSERROR (device->context, errcode); + return syserror (errcode); } } - return 0; + return DC_STATUS_SUCCESS; } diff --git a/src/serial_win32.c b/src/serial_win32.c index 56c3866..2d73cb9 100644 --- a/src/serial_win32.c +++ b/src/serial_win32.c @@ -25,9 +25,10 @@ #include #include "serial.h" +#include "common-private.h" #include "context-private.h" -struct serial_t { +struct dc_serial_t { /* Library context. */ dc_context_t *context; /* @@ -47,17 +48,34 @@ struct serial_t { unsigned int nbits; }; -int -serial_enumerate (serial_callback_t callback, void *userdata) +static dc_status_t +syserror(DWORD errcode) +{ + switch (errcode) { + case ERROR_INVALID_PARAMETER: + return DC_STATUS_INVALIDARGS; + case ERROR_OUTOFMEMORY: + return DC_STATUS_NOMEMORY; + case ERROR_FILE_NOT_FOUND: + return DC_STATUS_NODEVICE; + case ERROR_ACCESS_DENIED: + return DC_STATUS_NOACCESS; + default: + return DC_STATUS_IO; + } +} + +dc_status_t +dc_serial_enumerate (dc_serial_callback_t callback, void *userdata) { // Open the registry key. HKEY hKey; LONG rc = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &hKey); if (rc != ERROR_SUCCESS) { if (rc == ERROR_FILE_NOT_FOUND) - return 0; + return DC_STATUS_SUCCESS; else - return -1; + return DC_STATUS_IO; } // Get the number of values. @@ -65,7 +83,7 @@ serial_enumerate (serial_callback_t callback, void *userdata) rc = RegQueryInfoKey (hKey, NULL, NULL, NULL, NULL, NULL, NULL, &count, NULL, NULL, NULL, NULL); if (rc != ERROR_SUCCESS) { RegCloseKey(hKey); - return -1; + return DC_STATUS_IO; } for (DWORD i = 0; i < count; ++i) { @@ -77,7 +95,7 @@ serial_enumerate (serial_callback_t callback, void *userdata) rc = RegEnumValueA (hKey, i, name, &name_len, NULL, &type, (LPBYTE) data, &data_len); if (rc != ERROR_SUCCESS) { RegCloseKey(hKey); - return -1; + return DC_STATUS_IO; } // Ignore non-string values. @@ -87,7 +105,7 @@ serial_enumerate (serial_callback_t callback, void *userdata) // Prevent a possible buffer overflow. if (data_len >= sizeof (data)) { RegCloseKey(hKey); - return -1; + return DC_STATUS_NOMEMORY; } // Null terminate the string. @@ -98,18 +116,16 @@ serial_enumerate (serial_callback_t callback, void *userdata) RegCloseKey(hKey); - return 0; + return DC_STATUS_SUCCESS; } -// -// Open the serial port. -// - -int -serial_open (serial_t **out, dc_context_t *context, const char* name) +dc_status_t +dc_serial_open (dc_serial_t **out, dc_context_t *context, const char *name) { + dc_status_t status = DC_STATUS_SUCCESS; + if (out == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) + return DC_STATUS_INVALIDARGS; INFO (context, "Open: name=%s", name ? name : ""); @@ -119,7 +135,7 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) if (name && strncmp (name, buffer, 4) != 0) { size_t length = strlen (name) + 1; if (length + 4 > sizeof (buffer)) - return -1; + return DC_STATUS_NOMEMORY; memcpy (buffer + 4, name, length); devname = buffer; } else { @@ -127,10 +143,10 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) } // Allocate memory. - serial_t *device = (serial_t *) malloc (sizeof (serial_t)); + dc_serial_t *device = (dc_serial_t *) malloc (sizeof (dc_serial_t)); if (device == NULL) { SYSERROR (context, ERROR_OUTOFMEMORY); - return -1; // ERROR_OUTOFMEMORY (Not enough storage is available to complete this operation) + return DC_STATUS_NOMEMORY; } // Library context. @@ -149,7 +165,9 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) 0, // Non-overlapped I/O. NULL); if (device->hFile == INVALID_HANDLE_VALUE) { - SYSERROR (context, GetLastError ()); + DWORD errcode = GetLastError (); + SYSERROR (context, errcode); + status = syserror (errcode); goto error_free; } @@ -159,61 +177,57 @@ serial_open (serial_t **out, dc_context_t *context, const char* name) // represents a serial device. if (!GetCommState (device->hFile, &device->dcb) || !GetCommTimeouts (device->hFile, &device->timeouts)) { - SYSERROR (context, GetLastError ()); + DWORD errcode = GetLastError (); + SYSERROR (context, errcode); + status = syserror (errcode); goto error_close; } *out = device; - return 0; + return DC_STATUS_SUCCESS; error_close: CloseHandle (device->hFile); error_free: free (device); - return -1; + return status; } -// -// Close the serial port. -// - -int -serial_close (serial_t *device) +dc_status_t +dc_serial_close (dc_serial_t *device) { - int errcode = 0; + dc_status_t status = DC_STATUS_SUCCESS; if (device == NULL) - return 0; + return DC_STATUS_SUCCESS; // Restore the initial communication settings and timeouts. if (!SetCommState (device->hFile, &device->dcb) || !SetCommTimeouts (device->hFile, &device->timeouts)) { - SYSERROR (device->context, GetLastError ()); - errcode = -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + dc_status_set_error(&status, syserror (errcode)); } // Close the device. if (!CloseHandle (device->hFile)) { - SYSERROR (device->context, GetLastError ()); - errcode = -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + dc_status_set_error(&status, syserror (errcode)); } // Free memory. free (device); - return errcode; + return status; } -// -// Configure the serial port (baudrate, databits, parity, stopbits and flowcontrol). -// - -int -serial_configure (serial_t *device, int baudrate, int databits, int parity, int stopbits, int flowcontrol) +dc_status_t +dc_serial_configure (dc_serial_t *device, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol) { if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) + return DC_STATUS_INVALIDARGS; INFO (device->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i", baudrate, databits, parity, stopbits, flowcontrol); @@ -221,8 +235,9 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int // Retrieve the current settings. DCB dcb; if (!GetCommState (device->hFile, &dcb)) { - SYSERROR (device->context, GetLastError ()); - return -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + return syserror (errcode); } dcb.fBinary = TRUE; // Enable Binary Transmission @@ -235,40 +250,52 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int if (databits >= 5 && databits <= 8) dcb.ByteSize = databits; else - return -1; + return DC_STATUS_INVALIDARGS; // Parity checking. switch (parity) { - case SERIAL_PARITY_NONE: // No parity + case DC_PARITY_NONE: dcb.Parity = NOPARITY; dcb.fParity = FALSE; break; - case SERIAL_PARITY_EVEN: // Even parity + case DC_PARITY_EVEN: dcb.Parity = EVENPARITY; dcb.fParity = TRUE; break; - case SERIAL_PARITY_ODD: // Odd parity + case DC_PARITY_ODD: dcb.Parity = ODDPARITY; dcb.fParity = TRUE; break; + case DC_PARITY_MARK: + dcb.Parity = MARKPARITY; + dcb.fParity = TRUE; + break; + case DC_PARITY_SPACE: + dcb.Parity = SPACEPARITY; + dcb.fParity = TRUE; + break; default: - return -1; + return DC_STATUS_INVALIDARGS; } + // Stopbits. switch (stopbits) { - case 1: // One stopbit + case DC_STOPBITS_ONE: dcb.StopBits = ONESTOPBIT; break; - case 2: // Two stopbits + case DC_STOPBITS_ONEPOINTFIVE: + dcb.StopBits = ONE5STOPBITS; + break; + case DC_STOPBITS_TWO: dcb.StopBits = TWOSTOPBITS; break; default: - return -1; + return DC_STATUS_INVALIDARGS; } // Flow control. switch (flowcontrol) { - case SERIAL_FLOWCONTROL_NONE: // No flow control. + case DC_FLOWCONTROL_NONE: dcb.fInX = FALSE; dcb.fOutX = FALSE; dcb.fOutxCtsFlow = FALSE; @@ -276,7 +303,7 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int dcb.fDtrControl = DTR_CONTROL_ENABLE; dcb.fRtsControl = RTS_CONTROL_ENABLE; break; - case SERIAL_FLOWCONTROL_HARDWARE: // Hardware (RTS/CTS) flow control. + case DC_FLOWCONTROL_HARDWARE: dcb.fInX = FALSE; dcb.fOutX = FALSE; dcb.fOutxCtsFlow = TRUE; @@ -284,7 +311,7 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; break; - case SERIAL_FLOWCONTROL_SOFTWARE: // Software (XON/XOFF) flow control. + case DC_FLOWCONTROL_SOFTWARE: dcb.fInX = TRUE; dcb.fOutX = TRUE; dcb.fOutxCtsFlow = FALSE; @@ -293,38 +320,36 @@ serial_configure (serial_t *device, int baudrate, int databits, int parity, int dcb.fRtsControl = RTS_CONTROL_ENABLE; break; default: - return -1; + return DC_STATUS_INVALIDARGS; } // Apply the new settings. if (!SetCommState (device->hFile, &dcb)) { - SYSERROR (device->context, GetLastError ()); - return -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + return syserror (errcode); } device->baudrate = baudrate; device->nbits = 1 + databits + stopbits + (parity ? 1 : 0); - return 0; + return DC_STATUS_SUCCESS; } -// -// Configure the serial port (timeouts). -// - -int -serial_set_timeout (serial_t *device, long timeout) +dc_status_t +dc_serial_set_timeout (dc_serial_t *device, int timeout) { if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) + return DC_STATUS_INVALIDARGS; - INFO (device->context, "Timeout: value=%li", timeout); + INFO (device->context, "Timeout: value=%i", timeout); // Retrieve the current timeouts. COMMTIMEOUTS timeouts; if (!GetCommTimeouts (device->hFile, &timeouts)) { - SYSERROR (device->context, GetLastError ()); - return -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + return syserror (errcode); } // Update the settings. @@ -353,98 +378,102 @@ serial_set_timeout (serial_t *device, long timeout) // Activate the new timeouts. if (!SetCommTimeouts (device->hFile, &timeouts)) { - SYSERROR (device->context, GetLastError ()); - return -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + return syserror (errcode); } - return 0; + return DC_STATUS_SUCCESS; } -// -// Configure the serial port (recommended size of the input/output buffers). -// - -int -serial_set_queue_size (serial_t *device, unsigned int input, unsigned int output) +dc_status_t +dc_serial_set_halfduplex (dc_serial_t *device, unsigned int value) { if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) - - if (!SetupComm (device->hFile, input, output)) { - SYSERROR (device->context, GetLastError ()); - return -1; - } - - return 0; -} - - -int -serial_set_halfduplex (serial_t *device, int value) -{ - if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) + return DC_STATUS_INVALIDARGS; device->halfduplex = value; - return 0; + return DC_STATUS_SUCCESS; } - -int -serial_set_latency (serial_t *device, unsigned int milliseconds) +dc_status_t +dc_serial_set_latency (dc_serial_t *device, unsigned int value) { if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) + return DC_STATUS_INVALIDARGS; - return 0; + return DC_STATUS_SUCCESS; } -int -serial_read (serial_t *device, void* data, unsigned int size) +dc_status_t +dc_serial_read (dc_serial_t *device, void *data, size_t size, size_t *actual) { - if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) - + dc_status_t status = DC_STATUS_SUCCESS; DWORD dwRead = 0; - if (!ReadFile (device->hFile, data, size, &dwRead, NULL)) { - SYSERROR (device->context, GetLastError ()); - return -1; + + if (device == NULL) { + status = DC_STATUS_INVALIDARGS; + goto out; } + if (!ReadFile (device->hFile, data, size, &dwRead, NULL)) { + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + status = syserror (errcode); + goto out; + } + + if (dwRead != size) { + status = DC_STATUS_TIMEOUT; + } + +out: HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, dwRead); - return dwRead; + if (actual) + *actual = dwRead; + + return status; } - -int -serial_write (serial_t *device, const void* data, unsigned int size) +dc_status_t +dc_serial_write (dc_serial_t *device, const void *data, size_t size, size_t *actual) { - if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) + dc_status_t status = DC_STATUS_SUCCESS; + DWORD dwWritten = 0; + + if (device == NULL) { + status = DC_STATUS_INVALIDARGS; + goto out; + } LARGE_INTEGER begin, end, freq; if (device->halfduplex) { // Get the current time. if (!QueryPerformanceFrequency(&freq) || !QueryPerformanceCounter(&begin)) { - SYSERROR (device->context, GetLastError ()); - return -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + status = syserror (errcode); + goto out; } } - DWORD dwWritten = 0; if (!WriteFile (device->hFile, data, size, &dwWritten, NULL)) { - SYSERROR (device->context, GetLastError ()); - return -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + status = syserror (errcode); + goto out; } if (device->halfduplex) { // Get the current time. if (!QueryPerformanceCounter(&end)) { - SYSERROR (device->context, GetLastError ()); - return -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + status = syserror (errcode); + goto out; } // Calculate the elapsed time (microseconds). @@ -461,204 +490,195 @@ serial_write (serial_t *device, const void* data, unsigned int size) // The remaining time is rounded up to the nearest millisecond // because the Windows Sleep() function doesn't have a higher // resolution. - serial_sleep (device, (remaining + 999) / 1000); + dc_serial_sleep (device, (remaining + 999) / 1000); } } + if (dwWritten != size) { + status = DC_STATUS_TIMEOUT; + } + +out: HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, dwWritten); - return dwWritten; + if (actual) + *actual = dwWritten; + + return status; } - -int -serial_flush (serial_t *device, int queue) +dc_status_t +dc_serial_purge (dc_serial_t *device, dc_direction_t direction) { if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) + return DC_STATUS_INVALIDARGS; - INFO (device->context, "Flush: queue=%u, input=%i, output=%i", queue, - serial_get_received (device), - serial_get_transmitted (device)); + INFO (device->context, "Purge: direction=%u", direction); DWORD flags = 0; - switch (queue) { - case SERIAL_QUEUE_INPUT: + switch (direction) { + case DC_DIRECTION_INPUT: flags = PURGE_RXABORT | PURGE_RXCLEAR; break; - case SERIAL_QUEUE_OUTPUT: + case DC_DIRECTION_OUTPUT: flags = PURGE_TXABORT | PURGE_TXCLEAR; break; - default: + case DC_DIRECTION_ALL: flags = PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR; break; + default: + return DC_STATUS_INVALIDARGS; } if (!PurgeComm (device->hFile, flags)) { - SYSERROR (device->context, GetLastError ()); - return -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + return syserror (errcode); } - return 0; + return DC_STATUS_SUCCESS; } - -int -serial_send_break (serial_t *device) +dc_status_t +dc_serial_flush (dc_serial_t *device) { if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) + return DC_STATUS_INVALIDARGS; - if (!SetCommBreak (device->hFile)) { - SYSERROR (device->context, GetLastError ()); - return -1; + INFO (device->context, "Flush: none"); + + if (!FlushFileBuffers (device->hFile)) { + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + return syserror (errcode); } - Sleep (250); - - if (!ClearCommBreak (device->hFile)) { - SYSERROR (device->context, GetLastError ()); - return -1; - } - - return 0; + return DC_STATUS_SUCCESS; } - -int -serial_set_break (serial_t *device, int level) +dc_status_t +dc_serial_set_break (dc_serial_t *device, unsigned int level) { if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) + return DC_STATUS_INVALIDARGS; INFO (device->context, "Break: value=%i", level); if (level) { if (!SetCommBreak (device->hFile)) { - SYSERROR (device->context, GetLastError ()); - return -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + return syserror (errcode); } } else { if (!ClearCommBreak (device->hFile)) { - SYSERROR (device->context, GetLastError ()); - return -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + return syserror (errcode); } } - return 0; + return DC_STATUS_SUCCESS; } -int -serial_set_dtr (serial_t *device, int level) +dc_status_t +dc_serial_set_dtr (dc_serial_t *device, unsigned int level) { if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) + return DC_STATUS_INVALIDARGS; INFO (device->context, "DTR: value=%i", level); int status = (level ? SETDTR : CLRDTR); if (!EscapeCommFunction (device->hFile, status)) { - SYSERROR (device->context, GetLastError ()); - return -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + return syserror (errcode); } - return 0; + return DC_STATUS_SUCCESS; } - -int -serial_set_rts (serial_t *device, int level) +dc_status_t +dc_serial_set_rts (dc_serial_t *device, unsigned int level) { if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) + return DC_STATUS_INVALIDARGS; INFO (device->context, "RTS: value=%i", level); int status = (level ? SETRTS : CLRRTS); if (!EscapeCommFunction (device->hFile, status)) { - SYSERROR (device->context, GetLastError ()); - return -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + return syserror (errcode); } - return 0; + return DC_STATUS_SUCCESS; } - -int -serial_get_received (serial_t *device) +dc_status_t +dc_serial_get_available (dc_serial_t *device, size_t *value) { if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) + return DC_STATUS_INVALIDARGS; COMSTAT stats; if (!ClearCommError (device->hFile, NULL, &stats)) { - SYSERROR (device->context, GetLastError ()); - return -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + return syserror (errcode); } - return stats.cbInQue; + if (value) + *value = stats.cbInQue; + + return DC_STATUS_SUCCESS; } - -int -serial_get_transmitted (serial_t *device) +dc_status_t +dc_serial_get_lines (dc_serial_t *device, unsigned int *value) { + unsigned int lines = 0; + if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) - - COMSTAT stats; - - if (!ClearCommError (device->hFile, NULL, &stats)) { - SYSERROR (device->context, GetLastError ()); - return -1; - } - - return stats.cbOutQue; -} - - -int -serial_get_line (serial_t *device, int line) -{ - if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) + return DC_STATUS_INVALIDARGS; DWORD stats = 0; if (!GetCommModemStatus (device->hFile, &stats)) { - SYSERROR (device->context, GetLastError ()); - return -1; + DWORD errcode = GetLastError (); + SYSERROR (device->context, errcode); + return syserror (errcode); } - switch (line) { - case SERIAL_LINE_DCD: - return (stats & MS_RLSD_ON) == MS_RLSD_ON; - case SERIAL_LINE_CTS: - return (stats & MS_CTS_ON) == MS_CTS_ON; - case SERIAL_LINE_DSR: - return (stats & MS_DSR_ON) == MS_DSR_ON; - case SERIAL_LINE_RNG: - return (stats & MS_RING_ON) == MS_RING_ON; - default: - return -1; - } + if (stats & MS_RLSD_ON) + lines |= DC_LINE_DCD; + if (stats & MS_CTS_ON) + lines |= DC_LINE_CTS; + if (stats & MS_DSR_ON) + lines |= DC_LINE_DSR; + if (stats & MS_RING_ON) + lines |= DC_LINE_RNG; - return 0; + if (value) + *value = lines; + + return DC_STATUS_SUCCESS; } - -int -serial_sleep (serial_t *device, unsigned long timeout) +dc_status_t +dc_serial_sleep (dc_serial_t *device, unsigned int timeout) { if (device == NULL) - return -1; + return DC_STATUS_INVALIDARGS; - INFO (device->context, "Sleep: value=%lu", timeout); + INFO (device->context, "Sleep: value=%u", timeout); Sleep (timeout); - return 0; + return DC_STATUS_SUCCESS; } diff --git a/src/shearwater_common.c b/src/shearwater_common.c index a370c47..e4313e4 100644 --- a/src/shearwater_common.c +++ b/src/shearwater_common.c @@ -36,81 +36,78 @@ #define ESC_END 0xDC #define ESC_ESC 0xDD -#define EXITCODE(n) ((n) < 0 ? DC_STATUS_IO : DC_STATUS_TIMEOUT) - dc_status_t shearwater_common_open (shearwater_common_device_t *device, dc_context_t *context, const char *name) { dc_status_t status = DC_STATUS_SUCCESS; // Open the device. - int rc = dc_serial_native_open (&device->serial, context, name); - if (rc != DC_STATUS_SUCCESS) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - return rc; + return status; } // Set the serial communication protocol (115200 8N1). - rc = serial_configure (device->serial->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (3000ms). - if (serial_set_timeout (device->serial->port, 3000) == -1) { + status = dc_serial_set_timeout (device->port, 3000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); status = DC_STATUS_IO; goto error_close; } // Make sure everything is in a sane state. - serial_sleep (device->serial->port, 300); - device->serial->ops->flush (device->serial->port, SERIAL_QUEUE_BOTH); + dc_serial_sleep (device->port, 300); + dc_serial_purge (device->port, DC_DIRECTION_ALL); return DC_STATUS_SUCCESS; error_close: - device->serial->ops->close (device->serial->port); + dc_serial_close (device->port); return status; } dc_status_t -shearwater_common_custom_open (shearwater_common_device_t *device, dc_context_t *context, dc_serial_t *serial) +shearwater_common_custom_open (shearwater_common_device_t *device, dc_context_t *context, dc_serial_t *port) { dc_status_t status = DC_STATUS_SUCCESS; // Set the serial reference - device->serial = serial; + device->port = port; - if (serial->type == DC_TRANSPORT_SERIAL) { +// if (port->type == DC_TRANSPORT_SERIAL) { + if (1) { // Set the serial communication protocol (115200 8N1). - int rc = serial_configure (device->serial->port, 115200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 115200, 8, DC_PARITY_NONE, 1, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - device->serial->ops->close (device->serial->port); - return DC_STATUS_IO; + goto error_close; } } // Set the timeout for receiving data (3000ms). - if (device->serial->ops->set_timeout (device->serial->port, 3000) == -1) { + status = dc_serial_set_timeout (device->port, 3000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - device->serial->ops->close (device->serial->port); - status = DC_STATUS_IO; goto error_close; } // Make sure everything is in a sane state. - serial_sleep (device->serial->port, 300); - device->serial->ops->flush (device->serial->port, SERIAL_QUEUE_BOTH); + dc_serial_sleep (device->port, 300); + dc_serial_purge (device->port, DC_DIRECTION_ALL); return DC_STATUS_SUCCESS; error_close: - serial_close (device->serial->port); + dc_serial_close (device->port); return status; } @@ -119,11 +116,7 @@ dc_status_t shearwater_common_close (shearwater_common_device_t *device) { // Close the device. - if (device->serial->ops->close (device->serial->port) == -1) { - return DC_STATUS_IO; - } - - return DC_STATUS_SUCCESS; + return dc_serial_close (device->port); } @@ -189,7 +182,7 @@ shearwater_common_decompress_xor (unsigned char *data, unsigned int size) static dc_status_t shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned char data[], unsigned int size) { - int n = 0; + dc_status_t status = DC_STATUS_SUCCESS; const unsigned char end[] = {END}; const unsigned char esc_end[] = {ESC, ESC_END}; const unsigned char esc_esc[] = {ESC, ESC_ESC}; @@ -199,9 +192,9 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned #if 0 // Send an initial END character to flush out any data that may have // accumulated in the receiver due to line noise. - n = device->serial->ops->write (device->serial->port, end, sizeof (end)); - if (n != sizeof (end)) { - return EXITCODE(n); + status = dc_serial_write (device->port, end, sizeof (end), NULL); + if (status != DC_STATUS_SUCCESS) { + return status; } #endif @@ -228,9 +221,9 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned // Flush the buffer if necessary. if (nbytes + len + sizeof(end) > sizeof(buffer)) { - n = device->serial->ops->write (device->serial->port, buffer, nbytes); - if (n != nbytes) { - return EXITCODE(n); + status = dc_serial_write (device->port, buffer, nbytes, NULL); + if (status != DC_STATUS_SUCCESS) { + return status; } nbytes = 0; @@ -246,9 +239,9 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned nbytes += sizeof(end); // Flush the buffer. - n = device->serial->ops->write (device->serial->port, buffer, nbytes); - if (n != nbytes) { - return EXITCODE(n); + status = dc_serial_write (device->port, buffer, nbytes, NULL); + if (status != DC_STATUS_SUCCESS) { + return status; } return DC_STATUS_SUCCESS; @@ -258,6 +251,7 @@ shearwater_common_slip_write (shearwater_common_device_t *device, const unsigned static dc_status_t shearwater_common_slip_read (shearwater_common_device_t *device, unsigned char data[], unsigned int size, unsigned int *actual) { + dc_status_t status = DC_STATUS_SUCCESS; unsigned int received = 0; // Read bytes until a complete packet has been received. If the @@ -266,12 +260,11 @@ shearwater_common_slip_read (shearwater_common_device_t *device, unsigned char d // than the supplied buffer size. while (1) { unsigned char c = 0; - int n = 0; // Get a single character to process. - n = device->serial->ops->read (device->serial->port, &c, 1); - if (n != 1) { - return EXITCODE(n); + status = dc_serial_read (device->port, &c, 1, NULL); + if (status != DC_STATUS_SUCCESS) { + return status; } switch (c) { @@ -288,9 +281,9 @@ shearwater_common_slip_read (shearwater_common_device_t *device, unsigned char d case ESC: // If it's an ESC character, get another character and then // figure out what to store in the packet based on that. - n = device->serial->ops->read (device->serial->port, &c, 1); - if (n != 1) { - return EXITCODE(n); + status = dc_serial_read (device->port, &c, 1, NULL); + if (status != DC_STATUS_SUCCESS) { + return status; } // If it's not one of the two escaped characters, then we diff --git a/src/shearwater_common.h b/src/shearwater_common.h index 8e4112f..b060f7c 100644 --- a/src/shearwater_common.h +++ b/src/shearwater_common.h @@ -25,7 +25,6 @@ #include "device-private.h" #include "serial.h" -#include "libdivecomputer/custom_serial.h" #ifdef __cplusplus extern "C" { @@ -36,7 +35,7 @@ extern "C" { typedef struct shearwater_common_device_t { dc_device_t base; - dc_serial_t *serial; + dc_serial_t *port; } shearwater_common_device_t; dc_status_t diff --git a/src/shearwater_petrel.c b/src/shearwater_petrel.c index 27444d7..bb0c884 100644 --- a/src/shearwater_petrel.c +++ b/src/shearwater_petrel.c @@ -114,12 +114,12 @@ error_free: dc_status_t -shearwater_petrel_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial_t *serial) +shearwater_petrel_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial_t *port) { dc_status_t status = DC_STATUS_SUCCESS; shearwater_petrel_device_t *device = NULL; - if (out == NULL || serial == NULL || serial->port == NULL) + if (out == NULL || port == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. @@ -133,7 +133,7 @@ shearwater_petrel_device_custom_open (dc_device_t **out, dc_context_t *context, memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - status = shearwater_common_custom_open (&device->base, context, serial); + status = shearwater_common_custom_open (&device->base, context, port); if (status != DC_STATUS_SUCCESS) { goto error_free; } diff --git a/src/shearwater_predator.c b/src/shearwater_predator.c index 649ea88..068b318 100644 --- a/src/shearwater_predator.c +++ b/src/shearwater_predator.c @@ -100,12 +100,12 @@ error_free: dc_status_t -shearwater_predator_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial_t *serial) +shearwater_predator_device_custom_open (dc_device_t **out, dc_context_t *context, dc_serial_t *port) { dc_status_t status = DC_STATUS_SUCCESS; shearwater_predator_device_t *device = NULL; - if (out == NULL || serial == NULL || serial->port == NULL) + if (out == NULL || port == NULL) return DC_STATUS_INVALIDARGS; // Allocate memory. @@ -119,7 +119,7 @@ shearwater_predator_device_custom_open (dc_device_t **out, dc_context_t *context memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - status = shearwater_common_custom_open (&device->base, context, serial); + status = shearwater_common_custom_open (&device->base, context, port); if (status != DC_STATUS_SUCCESS) { goto error_free; } diff --git a/src/suunto_d9.c b/src/suunto_d9.c index dcacd99..00de2ee 100644 --- a/src/suunto_d9.c +++ b/src/suunto_d9.c @@ -33,11 +33,6 @@ #define ISINSTANCE(device) dc_device_isinstance((device), (const dc_device_vtable_t *) &suunto_d9_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define C_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) #define D4i 0x19 @@ -49,7 +44,7 @@ typedef struct suunto_d9_device_t { suunto_common2_device_t base; - serial_t *port; + dc_serial_t *port; } suunto_d9_device_t; static dc_status_t suunto_d9_device_packet (dc_device_t *abstract, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size); @@ -114,10 +109,10 @@ suunto_d9_device_autodetect (suunto_d9_device_t *device, unsigned int model) unsigned int idx = (hint + i) % C_ARRAY_SIZE(baudrates); // Adjust the baudrate. - int rc = serial_configure (device->port, baudrates[idx], 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, baudrates[idx], 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to set the terminal attributes."); - return DC_STATUS_IO; + return status; } // Try reading the version info. @@ -153,40 +148,38 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam device->port = NULL; // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (9600 8N1). - rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (3000 ms). - if (serial_set_timeout (device->port, 3000) == -1) { + status = dc_serial_set_timeout (device->port, 3000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Set the DTR line (power supply for the interface). - if (serial_set_dtr (device->port, 1) == -1) { + status = dc_serial_set_dtr (device->port, 1); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR line."); - status = DC_STATUS_IO; goto error_close; } // Give the interface 100 ms to settle and draw power up. - serial_sleep (device->port, 100); + dc_serial_sleep (device->port, 100); // Make sure everything is in a sane state. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); // Try to autodetect the protocol variant. status = suunto_d9_device_autodetect (device, model); @@ -210,7 +203,7 @@ suunto_d9_device_open (dc_device_t **out, dc_context_t *context, const char *nam return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -222,10 +215,12 @@ suunto_d9_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; suunto_d9_device_t *device = (suunto_d9_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -235,28 +230,29 @@ suunto_d9_device_close (dc_device_t *abstract) static dc_status_t suunto_d9_device_packet (dc_device_t *abstract, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size) { + dc_status_t status = DC_STATUS_SUCCESS; suunto_d9_device_t *device = (suunto_d9_device_t *) abstract; if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; // Clear RTS to send the command. - serial_set_rts (device->port, 0); + dc_serial_set_rts (device->port, 0); // Send the command to the dive computer. - int n = serial_write (device->port, command, csize); - if (n != csize) { + status = dc_serial_write (device->port, command, csize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Receive the echo. unsigned char echo[128] = {0}; assert (sizeof (echo) >= csize); - n = serial_read (device->port, echo, csize); - if (n != csize) { + status = dc_serial_read (device->port, echo, csize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the echo."); - return EXITCODE (n); + return status; } // Verify the echo. @@ -266,13 +262,13 @@ suunto_d9_device_packet (dc_device_t *abstract, const unsigned char command[], u } // Set RTS to receive the reply. - serial_set_rts (device->port, 1); + dc_serial_set_rts (device->port, 1); // Receive the answer of the dive computer. - n = serial_read (device->port, answer, asize); - if (n != asize) { + status = dc_serial_read (device->port, answer, asize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the header of the package. diff --git a/src/suunto_eon.c b/src/suunto_eon.c index 6e8375c..f7cab8f 100644 --- a/src/suunto_eon.c +++ b/src/suunto_eon.c @@ -33,16 +33,11 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &suunto_eon_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define SZ_MEMORY 0x900 typedef struct suunto_eon_device_t { suunto_common_device_t base; - serial_t *port; + dc_serial_t *port; } suunto_eon_device_t; static dc_status_t suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer); @@ -92,32 +87,30 @@ suunto_eon_device_open (dc_device_t **out, dc_context_t *context, const char *na device->port = NULL; // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (1200 8N2). - rc = serial_configure (device->port, 1200, 8, SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 1200, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (1000ms). - if (serial_set_timeout (device->port, 1000) == -1) { + status = dc_serial_set_timeout (device->port, 1000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Clear the RTS line. - if (serial_set_rts (device->port, 0)) { + status = dc_serial_set_rts (device->port, 0); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR/RTS line."); - status = DC_STATUS_IO; goto error_close; } @@ -126,7 +119,7 @@ suunto_eon_device_open (dc_device_t **out, dc_context_t *context, const char *na return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -138,10 +131,12 @@ suunto_eon_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; suunto_eon_device_t *device = (suunto_eon_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -151,6 +146,7 @@ suunto_eon_device_close (dc_device_t *abstract) static dc_status_t suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) { + dc_status_t status = DC_STATUS_SUCCESS; suunto_eon_device_t *device = (suunto_eon_device_t*) abstract; // Erase the current contents of the buffer and @@ -167,10 +163,10 @@ suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Send the command. unsigned char command[1] = {'P'}; - int rc = serial_write (device->port, command, sizeof (command)); - if (rc != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (rc); + return status; } // Receive the answer. @@ -181,8 +177,9 @@ suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) unsigned int len = 64; // Increase the packet size if more data is immediately available. - int available = serial_get_received (device->port); - if (available > len) + size_t available = 0; + status = dc_serial_get_available (device->port, &available); + if (status == DC_STATUS_SUCCESS && available > len) len = available; // Limit the packet size to the total size. @@ -190,10 +187,10 @@ suunto_eon_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) len = sizeof(answer) - nbytes; // Read the packet. - int n = serial_read (device->port, answer + nbytes, len); - if (n != len) { + status = dc_serial_read (device->port, answer + nbytes, len, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Update and emit a progress event. @@ -254,6 +251,7 @@ suunto_eon_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, v dc_status_t suunto_eon_device_write_name (dc_device_t *abstract, unsigned char data[], unsigned int size) { + dc_status_t status = DC_STATUS_SUCCESS; suunto_eon_device_t *device = (suunto_eon_device_t*) abstract; if (!ISINSTANCE (abstract)) @@ -265,10 +263,10 @@ suunto_eon_device_write_name (dc_device_t *abstract, unsigned char data[], unsig // Send the command. unsigned char command[21] = {'N'}; memcpy (command + 1, data, size); - int rc = serial_write (device->port, command, sizeof (command)); - if (rc != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (rc); + return status; } return DC_STATUS_SUCCESS; @@ -278,6 +276,7 @@ suunto_eon_device_write_name (dc_device_t *abstract, unsigned char data[], unsig dc_status_t suunto_eon_device_write_interval (dc_device_t *abstract, unsigned char interval) { + dc_status_t status = DC_STATUS_SUCCESS; suunto_eon_device_t *device = (suunto_eon_device_t*) abstract; if (!ISINSTANCE (abstract)) @@ -285,10 +284,10 @@ suunto_eon_device_write_interval (dc_device_t *abstract, unsigned char interval) // Send the command. unsigned char command[2] = {'T', interval}; - int rc = serial_write (device->port, command, sizeof (command)); - if (rc != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (rc); + return status; } return DC_STATUS_SUCCESS; diff --git a/src/suunto_eonsteel.c b/src/suunto_eonsteel.c index e0da495..4d88ee3 100644 --- a/src/suunto_eonsteel.c +++ b/src/suunto_eonsteel.c @@ -700,6 +700,7 @@ suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callbac dc_buffer_t *file; char pathname[64]; unsigned int time; + unsigned int count = 0; dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; if (get_file_list(eon, &de) < 0) @@ -712,8 +713,13 @@ suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callbac devinfo.serial = array_convert_str2num(eon->version + 0x10, 16); device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); + count = count_dir_entries(de); + if (count == 0) { + return DC_STATUS_SUCCESS; + } + file = dc_buffer_new(0); - progress.maximum = count_dir_entries(de); + progress.maximum = count; progress.current = 0; device_event_emit(abstract, DC_EVENT_PROGRESS, &progress); diff --git a/src/suunto_solution.c b/src/suunto_solution.c index d151352..9a8149e 100644 --- a/src/suunto_solution.c +++ b/src/suunto_solution.c @@ -32,11 +32,6 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &suunto_solution_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define SZ_MEMORY 256 #define RB_PROFILE_BEGIN 0x020 @@ -44,7 +39,7 @@ typedef struct suunto_solution_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; } suunto_solution_device_t; static dc_status_t suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer); @@ -83,32 +78,30 @@ suunto_solution_device_open (dc_device_t **out, dc_context_t *context, const cha device->port = NULL; // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (1200 8N2). - rc = serial_configure (device->port, 1200, 8, SERIAL_PARITY_NONE, 2, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 1200, 8, DC_PARITY_NONE, DC_STOPBITS_TWO, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (1000ms). - if (serial_set_timeout (device->port, 1000) == -1) { + status = dc_serial_set_timeout (device->port, 1000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Clear the RTS line. - if (serial_set_rts (device->port, 0)) { + status = dc_serial_set_rts (device->port, 0); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR/RTS line."); - status = DC_STATUS_IO; goto error_close; } @@ -117,7 +110,7 @@ suunto_solution_device_open (dc_device_t **out, dc_context_t *context, const cha return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -129,10 +122,12 @@ suunto_solution_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; suunto_solution_device_t *device = (suunto_solution_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -142,6 +137,7 @@ suunto_solution_device_close (dc_device_t *abstract) static dc_status_t suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) { + dc_status_t status = DC_STATUS_SUCCESS; suunto_solution_device_t *device = (suunto_solution_device_t*) abstract; // Erase the current contents of the buffer and @@ -158,20 +154,20 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) progress.maximum = SZ_MEMORY - 1 + 2; device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); - int n = 0; unsigned char command[3] = {0}; unsigned char answer[3] = {0}; // Assert DTR - serial_set_dtr (device->port, 1); + dc_serial_set_dtr (device->port, 1); // Send: 0xFF command[0] = 0xFF; - serial_write (device->port, command, 1); + dc_serial_write (device->port, command, 1, NULL); // Receive: 0x3F - n = serial_read (device->port, answer, 1); - if (n != 1) return EXITCODE (n); + status = dc_serial_read (device->port, answer, 1, NULL); + if (status != DC_STATUS_SUCCESS) + return status; if (answer[0] != 0x3F) WARNING (abstract->context, "Unexpected answer byte."); @@ -179,7 +175,7 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) command[0] = 0x4D; command[1] = 0x01; command[2] = 0x01; - serial_write (device->port, command, 3); + dc_serial_write (device->port, command, 3, NULL); // Update and emit a progress event. progress.current += 1; @@ -188,24 +184,26 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) data[0] = 0x00; for (unsigned int i = 1; i < SZ_MEMORY; ++i) { // Receive: 0x01, i, data[i] - n = serial_read (device->port, answer, 3); - if (n != 3) return EXITCODE (n); + status = dc_serial_read (device->port, answer, 3, NULL); + if (status != DC_STATUS_SUCCESS) + return status; if (answer[0] != 0x01 || answer[1] != i) WARNING (abstract->context, "Unexpected answer byte."); // Send: i command[0] = i; - serial_write (device->port, command, 1); + dc_serial_write (device->port, command, 1, NULL); // Receive: data[i] - n = serial_read (device->port, data + i, 1); - if (n != 1) return EXITCODE (n); + status = dc_serial_read (device->port, data + i, 1, NULL); + if (status != DC_STATUS_SUCCESS) + return status; if (data[i] != answer[2]) WARNING (abstract->context, "Unexpected answer byte."); // Send: 0x0D command[0] = 0x0D; - serial_write (device->port, command, 1); + dc_serial_write (device->port, command, 1, NULL); // Update and emit a progress event. progress.current += 1; @@ -213,28 +211,31 @@ suunto_solution_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) } // Receive: 0x02, 0x00, 0x80 - n = serial_read (device->port, answer, 3); - if (n != 3) return EXITCODE (n); + status = dc_serial_read (device->port, answer, 3, NULL); + if (status != DC_STATUS_SUCCESS) + return status; if (answer[0] != 0x02 || answer[1] != 0x00 || answer[2] != 0x80) WARNING (abstract->context, "Unexpected answer byte."); // Send: 0x80 command[0] = 0x80; - serial_write (device->port, command, 1); + dc_serial_write (device->port, command, 1, NULL); // Receive: 0x80 - n = serial_read (device->port, answer, 1); - if (n != 1) return EXITCODE (n); + status = dc_serial_read (device->port, answer, 1, NULL); + if (status != DC_STATUS_SUCCESS) + return status; if (answer[0] != 0x80) WARNING (abstract->context, "Unexpected answer byte."); // Send: 0x20 command[0] = 0x20; - serial_write (device->port, command, 1); + dc_serial_write (device->port, command, 1, NULL); // Receive: 0x3F - n = serial_read (device->port, answer, 1); - if (n != 1) return EXITCODE (n); + status = dc_serial_read (device->port, answer, 1, NULL); + if (status != DC_STATUS_SUCCESS) + return status; if (answer[0] != 0x3F) WARNING (abstract->context, "Unexpected answer byte."); diff --git a/src/suunto_vyper.c b/src/suunto_vyper.c index 8ec502f..2d9f3a9 100644 --- a/src/suunto_vyper.c +++ b/src/suunto_vyper.c @@ -34,11 +34,6 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &suunto_vyper_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) @@ -52,7 +47,7 @@ typedef struct suunto_vyper_device_t { suunto_common_device_t base; - serial_t *port; + dc_serial_t *port; } suunto_vyper_device_t; static dc_status_t suunto_vyper_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); @@ -112,47 +107,45 @@ suunto_vyper_device_open (dc_device_t **out, dc_context_t *context, const char * device->port = NULL; // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status= DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (2400 8O1). - rc = serial_configure (device->port, 2400, 8, SERIAL_PARITY_ODD, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 2400, 8, DC_PARITY_ODD, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (1000 ms). - if (serial_set_timeout (device->port, 1000) == -1) { + status = dc_serial_set_timeout (device->port, 1000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Set the DTR line (power supply for the interface). - if (serial_set_dtr (device->port, 1) == -1) { + status = dc_serial_set_dtr (device->port, 1); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR line."); - status = DC_STATUS_IO; goto error_close; } // Give the interface 100 ms to settle and draw power up. - serial_sleep (device->port, 100); + dc_serial_sleep (device->port, 100); // Make sure everything is in a sane state. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -164,10 +157,12 @@ suunto_vyper_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; suunto_vyper_device_t *device = (suunto_vyper_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -177,18 +172,19 @@ suunto_vyper_device_close (dc_device_t *abstract) static dc_status_t suunto_vyper_send (suunto_vyper_device_t *device, const unsigned char command[], unsigned int csize) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; - serial_sleep (device->port, 500); + dc_serial_sleep (device->port, 500); // Set RTS to send the command. - serial_set_rts (device->port, 1); + dc_serial_set_rts (device->port, 1); // Send the command to the dive computer. - int n = serial_write (device->port, command, csize); - if (n != csize) { + status = dc_serial_write (device->port, command, csize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // If the interface sends an echo back (which is the case for many clone @@ -202,11 +198,11 @@ suunto_vyper_send (suunto_vyper_device_t *device, const unsigned char command[], // receive the reply before RTS is cleared. We have to wait some time // before clearing RTS (around 30ms). But if we wait too long (> 500ms), // the reply disappears again. - serial_sleep (device->port, 200); - serial_flush (device->port, SERIAL_QUEUE_INPUT); + dc_serial_sleep (device->port, 200); + dc_serial_purge (device->port, DC_DIRECTION_INPUT); // Clear RTS to receive the reply. - serial_set_rts (device->port, 0); + dc_serial_set_rts (device->port, 0); return DC_STATUS_SUCCESS; } @@ -215,10 +211,11 @@ suunto_vyper_send (suunto_vyper_device_t *device, const unsigned char command[], static dc_status_t suunto_vyper_transfer (suunto_vyper_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size) { - assert (asize >= size + 2); - + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; + assert (asize >= size + 2); + if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; @@ -230,10 +227,10 @@ suunto_vyper_transfer (suunto_vyper_device_t *device, const unsigned char comman } // Receive the answer of the dive computer. - int n = serial_read (device->port, answer, asize); - if (n != asize) { + status = dc_serial_read (device->port, answer, asize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the header of the package. @@ -329,6 +326,7 @@ suunto_vyper_device_write (dc_device_t *abstract, unsigned int address, const un static dc_status_t suunto_vyper_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init, dc_event_progress_t *progress) { + dc_status_t status = DC_STATUS_SUCCESS; suunto_vyper_device_t *device = (suunto_vyper_device_t*) abstract; if (device_is_cancelled (abstract)) @@ -352,9 +350,10 @@ suunto_vyper_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init, dc unsigned int nbytes = 0; for (unsigned int npackages = 0;; ++npackages) { // Receive the header of the package. + size_t n = 0; unsigned char answer[SZ_PACKET + 3] = {0}; - int n = serial_read (device->port, answer, 2); - if (n != 2) { + status = dc_serial_read (device->port, answer, 2, &n); + if (status != DC_STATUS_SUCCESS) { // If no data is received because a timeout occured, we assume // the last package was already received and the transmission // can be finished. Unfortunately this is not 100% reliable, @@ -366,7 +365,7 @@ suunto_vyper_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init, dc if (n == 0 && npackages != 0) break; ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the header of the package. @@ -378,10 +377,10 @@ suunto_vyper_read_dive (dc_device_t *abstract, dc_buffer_t *buffer, int init, dc // Receive the remaining part of the package. unsigned char len = answer[1]; - n = serial_read (device->port, answer + 2, len + 1); - if (n != len + 1) { + status = dc_serial_read (device->port, answer + 2, len + 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the checksum of the package. diff --git a/src/suunto_vyper2.c b/src/suunto_vyper2.c index a0b07a4..7a0f26b 100644 --- a/src/suunto_vyper2.c +++ b/src/suunto_vyper2.c @@ -32,16 +32,11 @@ #define ISINSTANCE(device) dc_device_isinstance((device), (const dc_device_vtable_t *) &suunto_vyper2_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define HELO2 0x15 typedef struct suunto_vyper2_device_t { suunto_common2_device_t base; - serial_t *port; + dc_serial_t *port; } suunto_vyper2_device_t; static dc_status_t suunto_vyper2_device_packet (dc_device_t *abstract, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size); @@ -101,43 +96,41 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char device->port = NULL; // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (9600 8N1). - rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (3000 ms). - if (serial_set_timeout (device->port, 3000) == -1) { + status = dc_serial_set_timeout (device->port, 3000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Set the DTR line (power supply for the interface). - if (serial_set_dtr (device->port, 1) == -1) { + status = dc_serial_set_dtr (device->port, 1); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the DTR line."); - status = DC_STATUS_IO; goto error_close; } // Give the interface 100 ms to settle and draw power up. - serial_sleep (device->port, 100); + dc_serial_sleep (device->port, 100); // Make sure everything is in a sane state. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); // Enable half-duplex emulation. - serial_set_halfduplex (device->port, 1); + dc_serial_set_halfduplex (device->port, 1); // Read the version info. status = suunto_common2_device_version ((dc_device_t *) device, device->base.version, sizeof (device->base.version)); @@ -158,7 +151,7 @@ suunto_vyper2_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -170,10 +163,12 @@ suunto_vyper2_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; suunto_vyper2_device_t *device = (suunto_vyper2_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -183,31 +178,32 @@ suunto_vyper2_device_close (dc_device_t *abstract) static dc_status_t suunto_vyper2_device_packet (dc_device_t *abstract, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize, unsigned int size) { + dc_status_t status = DC_STATUS_SUCCESS; suunto_vyper2_device_t *device = (suunto_vyper2_device_t *) abstract; if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; - serial_sleep (device->port, 600); + dc_serial_sleep (device->port, 600); // Set RTS to send the command. - serial_set_rts (device->port, 1); + dc_serial_set_rts (device->port, 1); // Send the command to the dive computer. - int n = serial_write (device->port, command, csize); - if (n != csize) { + status = dc_serial_write (device->port, command, csize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Clear RTS to receive the reply. - serial_set_rts (device->port, 0); + dc_serial_set_rts (device->port, 0); // Receive the answer of the dive computer. - n = serial_read (device->port, answer, asize); - if (n != asize) { + status = dc_serial_read (device->port, answer, asize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the header of the package. diff --git a/src/uwatec_aladin.c b/src/uwatec_aladin.c index 47c0ee2..91b87a9 100644 --- a/src/uwatec_aladin.c +++ b/src/uwatec_aladin.c @@ -33,11 +33,6 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &uwatec_aladin_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define SZ_MEMORY 2048 #define RB_PROFILE_BEGIN 0x000 @@ -49,7 +44,7 @@ typedef struct uwatec_aladin_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; unsigned int timestamp; unsigned int devtime; dc_ticks_t systime; @@ -95,33 +90,37 @@ uwatec_aladin_device_open (dc_device_t **out, dc_context_t *context, const char device->devtime = 0; // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (19200 8N1). - rc = serial_configure (device->port, 19200, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 19200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (INFINITE). - if (serial_set_timeout (device->port, -1) == -1) { + status = dc_serial_set_timeout (device->port, -1); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } - // Clear the RTS line and set the DTR line. - if (serial_set_dtr (device->port, 1) == -1 || - serial_set_rts (device->port, 0) == -1) { - ERROR (context, "Failed to set the DTR/RTS line."); - status = DC_STATUS_IO; + // Set the DTR line. + status = dc_serial_set_dtr (device->port, 1); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to set the DTR line."); + goto error_close; + } + + // Clear the RTS line. + status = dc_serial_set_rts (device->port, 0); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to clear the RTS line."); goto error_close; } @@ -130,7 +129,7 @@ uwatec_aladin_device_open (dc_device_t **out, dc_context_t *context, const char return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -142,10 +141,12 @@ uwatec_aladin_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; uwatec_aladin_device_t *device = (uwatec_aladin_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -172,6 +173,7 @@ uwatec_aladin_device_set_fingerprint (dc_device_t *abstract, const unsigned char static dc_status_t uwatec_aladin_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) { + dc_status_t status = DC_STATUS_SUCCESS; uwatec_aladin_device_t *device = (uwatec_aladin_device_t*) abstract; // Erase the current contents of the buffer and @@ -193,10 +195,10 @@ uwatec_aladin_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; - int rc = serial_read (device->port, answer + i, 1); - if (rc != 1) { + status = dc_serial_read (device->port, answer + i, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (rc); + return status; } if (answer[i] == (i < 3 ? 0x55 : 0x00)) { i++; // Continue. @@ -214,10 +216,10 @@ uwatec_aladin_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); // Receive the remaining part of the package. - int rc = serial_read (device->port, answer + 4, sizeof (answer) - 4); - if (rc != sizeof (answer) - 4) { + status = dc_serial_read (device->port, answer + 4, sizeof (answer) - 4, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Unexpected EOF in answer."); - return EXITCODE (rc); + return status; } // Update and emit a progress event. diff --git a/src/uwatec_memomouse.c b/src/uwatec_memomouse.c index ba1153a..92e3044 100644 --- a/src/uwatec_memomouse.c +++ b/src/uwatec_memomouse.c @@ -33,11 +33,6 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &uwatec_memomouse_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define PACKETSIZE 126 #define ACK 0x60 @@ -45,7 +40,7 @@ typedef struct uwatec_memomouse_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; unsigned int timestamp; unsigned int devtime; dc_ticks_t systime; @@ -91,45 +86,49 @@ uwatec_memomouse_device_open (dc_device_t **out, dc_context_t *context, const ch device->devtime = 0; // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (9600 8N1). - rc = serial_configure (device->port, 9600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 9600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (1000 ms). - if (serial_set_timeout (device->port, 1000) == -1) { + status = dc_serial_set_timeout (device->port, 1000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } - // Clear the RTS and DTR lines. - if (serial_set_rts (device->port, 0) == -1 || - serial_set_dtr (device->port, 0) == -1) { - ERROR (context, "Failed to set the DTR/RTS line."); - status = DC_STATUS_IO; + // Clear the DTR line. + status = dc_serial_set_dtr (device->port, 0); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to clear the DTR line."); + goto error_close; + } + + // Clear the RTS line. + status = dc_serial_set_rts (device->port, 0); + if (status != DC_STATUS_SUCCESS) { + ERROR (context, "Failed to clear the RTS line."); goto error_close; } // Make sure everything is in a sane state. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); *out = (dc_device_t*) device; return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -141,10 +140,12 @@ uwatec_memomouse_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; uwatec_memomouse_device_t *device = (uwatec_memomouse_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -171,15 +172,16 @@ uwatec_memomouse_device_set_fingerprint (dc_device_t *abstract, const unsigned c static dc_status_t uwatec_memomouse_read_packet (uwatec_memomouse_device_t *device, unsigned char data[], unsigned int size, unsigned int *result) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; assert (result != NULL); // Receive the header of the package. - int rc = serial_read (device->port, data, 1); - if (rc != 1) { + status = dc_serial_read (device->port, data, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (rc); + return status; } // Reverse the bits. @@ -193,10 +195,10 @@ uwatec_memomouse_read_packet (uwatec_memomouse_device_t *device, unsigned char d } // Receive the remaining part of the package. - rc = serial_read (device->port, data + 1, len + 1); - if (rc != len + 1) { + status = dc_serial_read (device->port, data + 1, len + 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (rc); + return status; } // Reverse the bits. @@ -219,6 +221,7 @@ uwatec_memomouse_read_packet (uwatec_memomouse_device_t *device, unsigned char d static dc_status_t uwatec_memomouse_read_packet_outer (uwatec_memomouse_device_t *device, unsigned char data[], unsigned int size, unsigned int *result) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; dc_status_t rc = DC_STATUS_SUCCESS; @@ -229,14 +232,14 @@ uwatec_memomouse_read_packet_outer (uwatec_memomouse_device_t *device, unsigned return rc; // Flush the input buffer. - serial_flush (device->port, SERIAL_QUEUE_INPUT); + dc_serial_purge (device->port, DC_DIRECTION_INPUT); // Reject the packet. unsigned char value = NAK; - int n = serial_write (device->port, &value, 1); - if (n != 1) { + status = dc_serial_write (device->port, &value, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to reject the packet."); - return EXITCODE (n); + return status; } } @@ -247,6 +250,7 @@ uwatec_memomouse_read_packet_outer (uwatec_memomouse_device_t *device, unsigned static dc_status_t uwatec_memomouse_read_packet_inner (uwatec_memomouse_device_t *device, dc_buffer_t *buffer, dc_event_progress_t *progress) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; // Erase the current contents of the buffer. @@ -271,10 +275,10 @@ uwatec_memomouse_read_packet_inner (uwatec_memomouse_device_t *device, dc_buffer // Accept the packet. unsigned char value = ACK; - int n = serial_write (device->port, &value, 1); - if (n != 1) { + status = dc_serial_write (device->port, &value, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to accept the packet."); - return EXITCODE (n); + return status; } if (nbytes == 0) { @@ -329,29 +333,31 @@ uwatec_memomouse_read_packet_inner (uwatec_memomouse_device_t *device, dc_buffer static dc_status_t uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t *buffer) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; + size_t available = 0; // Enable progress notifications. dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; device_event_emit (&device->base, DC_EVENT_PROGRESS, &progress); // Waiting for greeting message. - while (serial_get_received (device->port) == 0) { + while (dc_serial_get_available (device->port, &available) == DC_STATUS_SUCCESS && available == 0) { if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; // Flush the input buffer. - serial_flush (device->port, SERIAL_QUEUE_INPUT); + dc_serial_purge (device->port, DC_DIRECTION_INPUT); // Reject the packet. unsigned char value = NAK; - int n = serial_write (device->port, &value, 1); - if (n != 1) { + status = dc_serial_write (device->port, &value, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to reject the packet."); - return EXITCODE (n); + return status; } - serial_sleep (device->port, 300); + dc_serial_sleep (device->port, 300); } // Read the ID string. @@ -374,27 +380,27 @@ uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t * // Wait a small amount of time before sending the command. // Without this delay, the transfer will fail most of the time. - serial_sleep (device->port, 50); + dc_serial_sleep (device->port, 50); // Keep send the command to the device, // until the ACK answer is received. unsigned char answer = NAK; while (answer == NAK) { // Flush the input buffer. - serial_flush (device->port, SERIAL_QUEUE_INPUT); + dc_serial_purge (device->port, DC_DIRECTION_INPUT); // Send the command to the device. - int n = serial_write (device->port, command, sizeof (command)); - if (n != sizeof (command)) { + status = dc_serial_write (device->port, command, sizeof (command), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Wait for the answer (ACK). - n = serial_read (device->port, &answer, 1); - if (n != 1) { + status = dc_serial_read (device->port, &answer, 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } } @@ -405,12 +411,12 @@ uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t * } // Wait for the data packet. - while (serial_get_received (device->port) == 0) { + while (dc_serial_get_available (device->port, &available) == DC_STATUS_SUCCESS && available == 0) { if (device_is_cancelled (abstract)) return DC_STATUS_CANCELLED; device_event_emit (&device->base, DC_EVENT_WAITING, NULL); - serial_sleep (device->port, 100); + dc_serial_sleep (device->port, 100); } // Fetch the current system time. @@ -438,7 +444,9 @@ uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t * static dc_status_t uwatec_memomouse_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) { + dc_status_t status = DC_STATUS_SUCCESS; uwatec_memomouse_device_t *device = (uwatec_memomouse_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Erase the current contents of the buffer. if (!dc_buffer_clear (buffer)) { @@ -448,24 +456,26 @@ uwatec_memomouse_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Give the interface some time to notice the DTR // line change from a previous transfer (if any). - serial_sleep (device->port, 500); + dc_serial_sleep (device->port, 500); // Set the DTR line. - if (serial_set_dtr (device->port, 1) == -1) { + rc = dc_serial_set_dtr (device->port, 1); + if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to set the RTS line."); - return DC_STATUS_IO; + return rc; } // Start the transfer. - dc_status_t rc = uwatec_memomouse_dump_internal (device, buffer); + status = uwatec_memomouse_dump_internal (device, buffer); // Clear the DTR line again. - if (serial_set_dtr (device->port, 0) == -1) { + rc = dc_serial_set_dtr (device->port, 0); + if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to set the RTS line."); - return DC_STATUS_IO; + return rc; } - return rc; + return status; } diff --git a/src/uwatec_meridian.c b/src/uwatec_meridian.c index e8de867..3e08f94 100644 --- a/src/uwatec_meridian.c +++ b/src/uwatec_meridian.c @@ -33,17 +33,12 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &uwatec_meridian_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define ACK 0x11 #define NAK 0x66 typedef struct uwatec_meridian_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; unsigned int timestamp; unsigned int devtime; dc_ticks_t systime; @@ -69,6 +64,7 @@ static const dc_device_vtable_t uwatec_meridian_device_vtable = { static dc_status_t uwatec_meridian_transfer (uwatec_meridian_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; assert (csize > 0 && csize <= 255); @@ -85,18 +81,18 @@ uwatec_meridian_transfer (uwatec_meridian_device_t *device, const unsigned char packet[11 + csize] = checksum_xor_uint8 (packet + 7, csize + 4, 0x00); // Send the packet. - int n = serial_write (device->port, packet, csize + 12); - if (n != csize + 12) { + status = dc_serial_write (device->port, packet, csize + 12, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Read the echo. unsigned char echo[sizeof(packet)]; - n = serial_read (device->port, echo, csize + 12); - if (n != csize + 12) { + status = dc_serial_read (device->port, echo, csize + 12, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the echo."); - return EXITCODE (n); + return status; } // Verify the echo. @@ -107,10 +103,10 @@ uwatec_meridian_transfer (uwatec_meridian_device_t *device, const unsigned char // Read the header. unsigned char header[6]; - n = serial_read (device->port, header, sizeof (header)); - if (n != sizeof (header)) { + status = dc_serial_read (device->port, header, sizeof (header), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the header."); - return EXITCODE (n); + return status; } // Verify the header. @@ -120,18 +116,18 @@ uwatec_meridian_transfer (uwatec_meridian_device_t *device, const unsigned char } // Read the packet. - n = serial_read (device->port, answer, asize); - if (n != asize) { + status = dc_serial_read (device->port, answer, asize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet."); - return EXITCODE (n); + return status; } // Read the checksum. unsigned char csum = 0x00; - n = serial_read (device->port, &csum, sizeof (csum)); - if (n != sizeof (csum)) { + status = dc_serial_read (device->port, &csum, sizeof (csum), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the checksum."); - return EXITCODE (n); + return status; } // Verify the checksum. @@ -207,30 +203,28 @@ uwatec_meridian_device_open (dc_device_t **out, dc_context_t *context, const cha device->devtime = 0; // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (57600 8N1). - rc = serial_configure (device->port, 57600, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 57600, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (3000ms). - if (serial_set_timeout (device->port, 3000) == -1) { + status = dc_serial_set_timeout (device->port, 3000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Make sure everything is in a sane state. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); // Perform the handshaking. uwatec_meridian_handshake (device); @@ -240,7 +234,7 @@ uwatec_meridian_device_open (dc_device_t **out, dc_context_t *context, const cha return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -252,10 +246,12 @@ uwatec_meridian_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; uwatec_meridian_device_t *device = (uwatec_meridian_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -282,6 +278,7 @@ uwatec_meridian_device_set_fingerprint (dc_device_t *abstract, const unsigned ch static dc_status_t uwatec_meridian_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) { + dc_status_t status = DC_STATUS_SUCCESS; uwatec_meridian_device_t *device = (uwatec_meridian_device_t*) abstract; dc_status_t rc = DC_STATUS_SUCCESS; @@ -395,10 +392,10 @@ uwatec_meridian_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) // Read the header. unsigned char header[5]; - int n = serial_read (device->port, header, sizeof (header)); - if (n != sizeof (header)) { + status = dc_serial_read (device->port, header, sizeof (header), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the header."); - return EXITCODE (n); + return status; } // Get the packet size. @@ -409,18 +406,18 @@ uwatec_meridian_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) } // Read the packet data. - n = serial_read (device->port, data + nbytes, packetsize - 1); - if (n != packetsize - 1) { + status = dc_serial_read (device->port, data + nbytes, packetsize - 1, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the packet."); - return EXITCODE (n); + return status; } // Read the checksum. unsigned char csum = 0x00; - n = serial_read (device->port, &csum, sizeof (csum)); - if (n != sizeof (csum)) { + status = dc_serial_read (device->port, &csum, sizeof (csum), NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the checksum."); - return EXITCODE (n); + return status; } // Verify the checksum. diff --git a/src/uwatec_smart.c b/src/uwatec_smart.c index 065943f..3c55f07 100644 --- a/src/uwatec_smart.c +++ b/src/uwatec_smart.c @@ -31,14 +31,9 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &uwatec_smart_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - typedef struct uwatec_smart_device_t { dc_device_t base; - irda_t *socket; + dc_irda_t *socket; unsigned int address; unsigned int timestamp; unsigned int devtime; @@ -88,18 +83,19 @@ uwatec_smart_discovery (unsigned int address, const char *name, unsigned int cha static dc_status_t uwatec_smart_transfer (uwatec_smart_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; - int n = irda_socket_write (device->socket, command, csize); - if (n != csize) { + status = dc_irda_write (device->socket, command, csize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } - n = irda_socket_read (device->socket, answer, asize); - if (n != asize) { + status = dc_irda_read (device->socket, answer, asize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } return DC_STATUS_SUCCESS; @@ -167,18 +163,16 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context) device->devtime = 0; // Open the irda socket. - int rc = irda_socket_open (&device->socket, context); - if (rc == -1) { + status = dc_irda_open (&device->socket, context); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the irda socket."); - status = DC_STATUS_IO; goto error_free; } // Discover the device. - rc = irda_socket_discover (device->socket, uwatec_smart_discovery, device); - if (rc == -1) { + status = dc_irda_discover (device->socket, uwatec_smart_discovery, device); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to discover the device."); - status = DC_STATUS_IO; goto error_close; } @@ -189,10 +183,9 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context) } // Connect the device. - rc = irda_socket_connect_lsap (device->socket, device->address, 1); - if (rc == -1) { + status = dc_irda_connect_lsap (device->socket, device->address, 1); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to connect the device."); - status = DC_STATUS_IO; goto error_close; } @@ -204,7 +197,7 @@ uwatec_smart_device_open (dc_device_t **out, dc_context_t *context) return DC_STATUS_SUCCESS; error_close: - irda_socket_close (device->socket); + dc_irda_close (device->socket); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -216,10 +209,12 @@ uwatec_smart_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; uwatec_smart_device_t *device = (uwatec_smart_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (irda_socket_close (device->socket) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_irda_close (device->socket); + if (status != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status; @@ -360,25 +355,26 @@ uwatec_smart_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) unsigned int len = 32; // Increase the packet size if more data is immediately available. - int available = irda_socket_available (device->socket); - if (available > len) + size_t available = 0; + rc = dc_irda_get_available (device->socket, &available); + if (rc == DC_STATUS_SUCCESS && available > len) len = available; // Limit the packet size to the total size. if (nbytes + len > length) len = length - nbytes; - int n = irda_socket_read (device->socket, data + nbytes, len); - if (n != len) { + rc = dc_irda_read (device->socket, data + nbytes, len, NULL); + if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return rc; } // Update and emit a progress event. - progress.current += n; + progress.current += len; device_event_emit (&device->base, DC_EVENT_PROGRESS, &progress); - nbytes += n; + nbytes += len; } return DC_STATUS_SUCCESS; diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index eaa72d6..feb4844 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -46,6 +46,7 @@ #define SMARTZ 0x1C #define MERIDIAN 0x20 #define CHROMIS 0x24 +#define MANTIS2 0x26 #define UNSUPPORTED 0xFFFFFFFF @@ -58,6 +59,11 @@ #define FRESH 1.000 #define SALT 1.025 +#define FREEDIVE1 0x00000080 +#define FREEDIVE2 0x00000200 +#define GAUGE 0x00001000 +#define SALINITY 0x00100000 + typedef enum { PRESSURE_DEPTH, RBT, @@ -91,8 +97,8 @@ typedef struct uwatec_smart_header_info_t { unsigned int temp_maximum; unsigned int temp_surface; unsigned int tankpressure; - unsigned int salinity; unsigned int timezone; + unsigned int settings; } uwatec_smart_header_info_t; typedef struct uwatec_smart_sample_info_t { @@ -144,6 +150,7 @@ struct uwatec_smart_parser_t { unsigned int ntanks; uwatec_smart_tank_t tank[NGASMIXES]; dc_water_t watertype; + dc_divemode_t divemode; }; static dc_status_t uwatec_smart_parser_set_data (dc_parser_t *abstract, const unsigned char *data, unsigned int size); @@ -170,8 +177,8 @@ uwatec_smart_header_info_t uwatec_smart_pro_header = { UNSUPPORTED, /* temp_maximum */ UNSUPPORTED, /* temp_surface */ UNSUPPORTED, /* tankpressure */ - UNSUPPORTED, /* salinity */ UNSUPPORTED, /* timezone */ + UNSUPPORTED, /* settings */ }; static const @@ -183,8 +190,8 @@ uwatec_smart_header_info_t uwatec_smart_galileo_header = { 28, /* temp_maximum */ 32, /* temp_surface */ 50, /* tankpressure */ - 94, /* salinity */ 16, /* timezone */ + 92, /* settings */ }; static const @@ -196,8 +203,8 @@ uwatec_smart_header_info_t uwatec_smart_aladin_tec_header = { 28, /* temp_maximum */ 32, /* temp_surface */ UNSUPPORTED, /* tankpressure */ - UNSUPPORTED, /* salinity */ 16, /* timezone */ + 52, /* settings */ }; static const @@ -209,8 +216,8 @@ uwatec_smart_header_info_t uwatec_smart_aladin_tec2g_header = { 28, /* temp_maximum */ 32, /* temp_surface */ UNSUPPORTED, /* tankpressure */ - UNSUPPORTED, /* salinity */ - UNSUPPORTED, /* timezone */ + 16, /* timezone */ + 60, /* settings */ }; static const @@ -222,8 +229,8 @@ uwatec_smart_header_info_t uwatec_smart_com_header = { UNSUPPORTED, /* temp_maximum */ UNSUPPORTED, /* temp_surface */ 30, /* tankpressure */ - UNSUPPORTED, /* salinity */ UNSUPPORTED, /* timezone */ + UNSUPPORTED, /* settings */ }; static const @@ -235,8 +242,8 @@ uwatec_smart_header_info_t uwatec_smart_tec_header = { UNSUPPORTED, /* temp_maximum */ UNSUPPORTED, /* temp_surface */ 34, /* tankpressure */ - UNSUPPORTED, /* salinity */ UNSUPPORTED, /* timezone */ + UNSUPPORTED, /* settings */ }; static const @@ -435,6 +442,40 @@ uwatec_smart_parser_cache (uwatec_smart_parser_t *parser) } } + // Get the settings. + dc_divemode_t divemode = DC_DIVEMODE_OC; + dc_water_t watertype = DC_WATER_FRESH; + if (header->settings != UNSUPPORTED) { + unsigned int settings = array_uint32_le (data + header->settings); + + // Get the freedive/gauge bits. + unsigned int freedive = 0; + unsigned int gauge = (settings & GAUGE) != 0; + if (parser->model == ALADINTEC) { + freedive = 0; + } else if (parser->model == ALADINTEC2G) { + freedive = (settings & FREEDIVE2) != 0; + } else { + freedive = (settings & FREEDIVE1) != 0; + } + + // Get the dive mode. The freedive bit needs to be checked + // first, because freedives have both the freedive and gauge + // bits set. + if (freedive) { + divemode = DC_DIVEMODE_FREEDIVE; + } else if (gauge) { + divemode = DC_DIVEMODE_GAUGE; + } else { + divemode = DC_DIVEMODE_OC; + } + + // Get the water type. + if (settings & SALINITY) { + watertype = DC_WATER_SALT; + } + } + // Get the gas mixes and tanks. unsigned int ntanks = 0; unsigned int ngasmixes = 0; @@ -460,10 +501,11 @@ uwatec_smart_parser_cache (uwatec_smart_parser_t *parser) unsigned int beginpressure = 0; unsigned int endpressure = 0; - if (header->tankpressure != UNSUPPORTED) { + if (header->tankpressure != UNSUPPORTED && + divemode != DC_DIVEMODE_FREEDIVE) { if (parser->model == GALILEO || parser->model == GALILEOTRIMIX || parser->model == ALADIN2G || parser->model == MERIDIAN || - parser->model == CHROMIS) { + parser->model == CHROMIS || parser->model == MANTIS2) { unsigned int offset = header->tankpressure + 2 * i; endpressure = array_uint16_le(data + offset); beginpressure = array_uint16_le(data + offset + 2 * header->ngases); @@ -484,14 +526,6 @@ uwatec_smart_parser_cache (uwatec_smart_parser_t *parser) } } - // Get the water type. - dc_water_t watertype = DC_WATER_FRESH; - if (header->salinity != UNSUPPORTED) { - if (data[header->salinity] & 0x10) { - watertype = DC_WATER_SALT; - } - } - // Cache the data for later use. parser->trimix = trimix; parser->ngasmixes = ngasmixes; @@ -503,6 +537,7 @@ uwatec_smart_parser_cache (uwatec_smart_parser_t *parser) parser->tank[i] = tank[i]; } parser->watertype = watertype; + parser->divemode = divemode; parser->cached = HEADER; return DC_STATUS_SUCCESS; @@ -547,6 +582,7 @@ uwatec_smart_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i case ALADIN2G: case MERIDIAN: case CHROMIS: + case MANTIS2: parser->headersize = 152; parser->header = &uwatec_smart_galileo_header; parser->samples = uwatec_smart_galileo_samples; @@ -612,6 +648,7 @@ uwatec_smart_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i parser->tank[i].gasmix = 0; } parser->watertype = DC_WATER_FRESH; + parser->divemode = DC_DIVEMODE_OC; *out = (dc_parser_t*) parser; @@ -643,6 +680,7 @@ uwatec_smart_parser_set_data (dc_parser_t *abstract, const unsigned char *data, parser->tank[i].gasmix = 0; } parser->watertype = DC_WATER_FRESH; + parser->divemode = DC_DIVEMODE_OC; return DC_STATUS_SUCCESS; } @@ -754,13 +792,12 @@ uwatec_smart_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi *((double *) value) = (signed short) array_uint16_le (data + table->temp_surface) / 10.0; break; case DC_FIELD_DIVEMODE: - if (parser->ngasmixes) - *((dc_divemode_t *) value) = DC_DIVEMODE_OC; - else - *((dc_divemode_t *) value) = DC_DIVEMODE_GAUGE; + if (table->settings == UNSUPPORTED) + return DC_STATUS_UNSUPPORTED; + *((dc_divemode_t *) value) = parser->divemode; break; case DC_FIELD_SALINITY: - if (table->salinity == UNSUPPORTED) + if (table->settings == UNSUPPORTED) return DC_STATUS_UNSUPPORTED; water->type = parser->watertype; water->density = salinity * 1000.0; @@ -880,6 +917,11 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t double salinity = (parser->watertype == DC_WATER_SALT ? SALT : FRESH); + unsigned int interval = 4; + if (parser->divemode == DC_DIVEMODE_FREEDIVE) { + interval = 1; + } + int have_depth = 0, have_temperature = 0, have_pressure = 0, have_rbt = 0, have_heartrate = 0, have_bearing = 0; @@ -891,7 +933,7 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t unsigned int id = 0; if (parser->model == GALILEO || parser->model == GALILEOTRIMIX || parser->model == ALADIN2G || parser->model == MERIDIAN || - parser->model == CHROMIS) { + parser->model == CHROMIS || parser->model == MANTIS2) { // Uwatec Galileo id = uwatec_galileo_identify (data[offset]); } else { @@ -1166,7 +1208,7 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t if (callback) callback (DC_SAMPLE_DEPTH, sample, userdata); } - time += 4; + time += interval; complete--; } } diff --git a/src/zeagle_n2ition3.c b/src/zeagle_n2ition3.c index ae76696..516dd57 100644 --- a/src/zeagle_n2ition3.c +++ b/src/zeagle_n2ition3.c @@ -34,11 +34,6 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &zeagle_n2ition3_device_vtable) -#define EXITCODE(rc) \ -( \ - rc == -1 ? DC_STATUS_IO : DC_STATUS_TIMEOUT \ -) - #define SZ_MEMORY 0x8000 #define SZ_PACKET 64 @@ -51,7 +46,7 @@ typedef struct zeagle_n2ition3_device_t { dc_device_t base; - serial_t *port; + dc_serial_t *port; unsigned char fingerprint[16]; } zeagle_n2ition3_device_t; @@ -76,6 +71,7 @@ static const dc_device_vtable_t zeagle_n2ition3_device_vtable = { static dc_status_t zeagle_n2ition3_packet (zeagle_n2ition3_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize) { + dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; assert (asize >= csize + 5); @@ -84,17 +80,17 @@ zeagle_n2ition3_packet (zeagle_n2ition3_device_t *device, const unsigned char co return DC_STATUS_CANCELLED; // Send the command to the device. - int n = serial_write (device->port, command, csize); - if (n != csize) { + status = dc_serial_write (device->port, command, csize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); - return EXITCODE (n); + return status; } // Receive the answer of the device. - n = serial_read (device->port, answer, asize); - if (n != asize) { + status = dc_serial_read (device->port, answer, asize, NULL); + if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); - return EXITCODE (n); + return status; } // Verify the echo. @@ -156,30 +152,28 @@ zeagle_n2ition3_device_open (dc_device_t **out, dc_context_t *context, const cha memset (device->fingerprint, 0, sizeof (device->fingerprint)); // Open the device. - int rc = serial_open (&device->port, context, name); - if (rc == -1) { + status = dc_serial_open (&device->port, context, name); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to open the serial port."); - status = DC_STATUS_IO; goto error_free; } // Set the serial communication protocol (4800 8N1). - rc = serial_configure (device->port, 4800, 8, SERIAL_PARITY_NONE, 1, SERIAL_FLOWCONTROL_NONE); - if (rc == -1) { + status = dc_serial_configure (device->port, 4800, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the terminal attributes."); - status = DC_STATUS_IO; goto error_close; } // Set the timeout for receiving data (1000 ms). - if (serial_set_timeout (device->port, 1000) == -1) { + status = dc_serial_set_timeout (device->port, 1000); + if (status != DC_STATUS_SUCCESS) { ERROR (context, "Failed to set the timeout."); - status = DC_STATUS_IO; goto error_close; } // Make sure everything is in a sane state. - serial_flush (device->port, SERIAL_QUEUE_BOTH); + dc_serial_purge (device->port, DC_DIRECTION_ALL); // Send the init commands. zeagle_n2ition3_init (device); @@ -189,7 +183,7 @@ zeagle_n2ition3_device_open (dc_device_t **out, dc_context_t *context, const cha return DC_STATUS_SUCCESS; error_close: - serial_close (device->port); + dc_serial_close (device->port); error_free: dc_device_deallocate ((dc_device_t *) device); return status; @@ -201,10 +195,12 @@ zeagle_n2ition3_device_close (dc_device_t *abstract) { dc_status_t status = DC_STATUS_SUCCESS; zeagle_n2ition3_device_t *device = (zeagle_n2ition3_device_t*) abstract; + dc_status_t rc = DC_STATUS_SUCCESS; // Close the device. - if (serial_close (device->port) == -1) { - dc_status_set_error(&status, DC_STATUS_IO); + rc = dc_serial_close (device->port); + if (rc != DC_STATUS_SUCCESS) { + dc_status_set_error(&status, rc); } return status;