Merge git://git.libdivecomputer.org/libdivecomputer into Subsurface-branch
This is a rough merge of the upstream libdivecomputer changes. I say "rough", because this disables the custom serial code as it clashes very badly with Jef's new dc_serial_t abstraction. Anton Lundin has patches on top of this to re-introduce the custom code in a way that integrates better with the upstream libdivecomputer state. * git://git.libdivecomputer.org/libdivecomputer: (42 commits) Add support for the Sherwood Vision. Fix the decoding of the maximum depth. Improve the default layout detection. Add a warning for unsupported devices. Fix the temperature for the Tusa Zen Air. Add support for the Aqualung i550T. Use the new settings field for the salinity. Fix the parsing of freedives. Detect the gauge and freedive mode correctly. Add the salinity field for the Aladin Tec. Add support for the Scubapro Mantis 2. Fix the decoding of the dive time. Add support for the Scubapro Mantis. Fix the Aeris 500AI serial number. Add the serial number encoding to the layout. Add salinity and timezone fields to Aladin Tec 2G Add NDL and RBT for the ATOM31 and I450T Add support for the new extended hardware descriptor. Update the OSTC device descriptors. Add a workaround for an OSTC4 firmware bug. ...
This commit is contained in:
commit
f9db4ca97c
@ -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)
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -55,5 +55,4 @@ libdivecomputer_HEADERS = \
|
||||
divesystem.h \
|
||||
divesystem_idive.h \
|
||||
cochran.h \
|
||||
cochran_commander.h \
|
||||
custom_serial.h
|
||||
cochran_commander.h
|
||||
|
||||
@ -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 <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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 */
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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 <libdivecomputer/custom_serial.h>
|
||||
#include <serial.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
143
src/hw_ostc.c
143
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;
|
||||
|
||||
165
src/hw_ostc3.c
165
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;
|
||||
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;
|
||||
|
||||
@ -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];
|
||||
|
||||
229
src/irda.c
229
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;
|
||||
}
|
||||
|
||||
152
src/irda.h
152
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 <libdivecomputer/common.h>
|
||||
#include <libdivecomputer/context.h>
|
||||
|
||||
#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 */
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,7 +65,8 @@ 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 = {
|
||||
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 */
|
||||
@ -79,6 +75,9 @@ static const dc_device_vtable_t oceanic_atom2_device_vtable = {
|
||||
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,16 +673,30 @@ 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 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;
|
||||
|
||||
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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free (profiles);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
free (logbooks);
|
||||
free (profiles);
|
||||
dc_buffer_free (logbook);
|
||||
|
||||
return status;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -31,29 +31,25 @@
|
||||
#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 = {
|
||||
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 */
|
||||
@ -62,9 +58,12 @@ static const dc_device_vtable_t oceanic_veo250_device_vtable = {
|
||||
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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
|
||||
#include <string.h> // memcpy
|
||||
#include <stdlib.h> // malloc, free
|
||||
#include <assert.h>
|
||||
|
||||
#include <libdivecomputer/oceanic_vtpro.h>
|
||||
|
||||
@ -30,30 +31,37 @@
|
||||
#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 = {
|
||||
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 */
|
||||
@ -62,6 +70,9 @@ static const dc_device_vtable_t oceanic_vtpro_device_vtable = {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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,9 +583,9 @@ oceanic_vtpro_device_version (dc_device_t *abstract, unsigned char data[], unsig
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
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};
|
||||
@ -454,6 +610,10 @@ oceanic_vtpro_device_version (dc_device_t *abstract, unsigned char data[], unsig
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -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,12 +111,24 @@ 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) {
|
||||
// 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)
|
||||
@ -115,12 +138,14 @@ oceanic_vtpro_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim
|
||||
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);
|
||||
|
||||
|
||||
78
src/parser.c
78
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)
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
334
src/serial.h
334
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 <libdivecomputer/common.h>
|
||||
#include <libdivecomputer/context.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include <libdivecomputer/custom_serial.h>
|
||||
/**
|
||||
* 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 */
|
||||
|
||||
@ -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;
|
||||
}
|
||||
INFO (device->context, "Flush: none");
|
||||
|
||||
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; // 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;
|
||||
}
|
||||
|
||||
@ -25,9 +25,10 @@
|
||||
#include <windows.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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.");
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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--;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user