From ffa3c4859327a78288cfb74e633ac3845a86ed86 Mon Sep 17 00:00:00 2001 From: Anton Lundin Date: Sat, 17 Sep 2016 17:27:56 +0200 Subject: Rewrite libdivecomputer custom serial code This rewrites the custom serial code to use the new api which I implemented in the Subsurface-branch of libdivecomputer. This is a bit to big patch but I haven't had the time to break it down into more sensible patches. This rewrite enables us to support more ftdi based divecomputer communication and is tested with both a OSTC3, OSTC2N and a Suunto Vyper, all over the libftdi driver. The bluetooth code paths are tested to, and should work as before. Signed-off-by: Anton Lundin Signed-off-by: Dirk Hohndel --- core/configuredivecomputer.cpp | 12 +- core/configuredivecomputerthreads.cpp | 10 -- core/libdivecomputer.c | 8 +- core/libdivecomputer.h | 8 +- core/qtserialbluetooth.cpp | 135 +++++++------- core/serial_ftdi.c | 322 ++++++++++++++-------------------- 6 files changed, 203 insertions(+), 292 deletions(-) diff --git a/core/configuredivecomputer.cpp b/core/configuredivecomputer.cpp index 2457ffe82..d8aefaecc 100644 --- a/core/configuredivecomputer.cpp +++ b/core/configuredivecomputer.cpp @@ -633,22 +633,18 @@ QString ConfigureDiveComputer::dc_open(device_data_t *data) } #if defined(SSRF_CUSTOM_SERIAL) - dc_serial_t *serial_device = NULL; - if (data->bluetooth_mode) { -#ifdef BT_SUPPORT - rc = dc_serial_qt_open(&serial_device, data->context, data->devname); +#if defined(BT_SUPPORT) && defined(SSRF_CUSTOM_SERIAL) + rc = dc_context_set_custom_serial(data->context, get_qt_serial_ops()); #endif #ifdef SERIAL_FTDI } else if (!strcmp(data->devname, "ftdi")) { - rc = dc_serial_ftdi_open(&serial_device, data->context); + rc = dc_context_set_custom_serial(data->context, &serial_ftdi_ops); #endif } if (rc != DC_STATUS_SUCCESS) { - return errmsg(rc); - } else if (serial_device) { - rc = dc_device_custom_open(&data->device, data->context, data->descriptor, serial_device); + report_error(errmsg(rc)); } else { #else { diff --git a/core/configuredivecomputerthreads.cpp b/core/configuredivecomputerthreads.cpp index c86c0966c..33791d737 100644 --- a/core/configuredivecomputerthreads.cpp +++ b/core/configuredivecomputerthreads.cpp @@ -100,16 +100,6 @@ static dc_status_t local_dc_device_open(dc_device_t **out, dc_context_t *context } #define dc_device_open local_dc_device_open -// Fake the custom open function -static dc_status_t local_dc_device_custom_open(dc_device_t **out, dc_context_t *context, dc_descriptor_t *descriptor, dc_serial_t *serial) -{ - if (strcmp(dc_descriptor_get_vendor(descriptor), "Heinrichs Weikamp") == 0 &&strcmp(dc_descriptor_get_product(descriptor), "OSTC 2N") == 0) - return DC_STATUS_SUCCESS; - else - return dc_device_custom_open(out, context, descriptor, serial); -} -#define dc_device_custom_open local_dc_device_custom_open - static dc_status_t local_hw_ostc_device_eeprom_read(void *ignored, unsigned char bank, unsigned char data[], unsigned int data_size) { FILE *f; diff --git a/core/libdivecomputer.c b/core/libdivecomputer.c index 92e61b92c..cd1b69bde 100644 --- a/core/libdivecomputer.c +++ b/core/libdivecomputer.c @@ -1026,22 +1026,18 @@ const char *do_libdivecomputer_import(device_data_t *data) err = translate("gettextFromC", "Unable to open %s %s (%s)"); #if defined(SSRF_CUSTOM_SERIAL) - dc_serial_t *serial_device = NULL; - if (data->bluetooth_mode) { #if defined(BT_SUPPORT) && defined(SSRF_CUSTOM_SERIAL) - rc = dc_serial_qt_open(&serial_device, data->context, data->devname); + rc = dc_context_set_custom_serial(data->context, get_qt_serial_ops()); #endif #ifdef SERIAL_FTDI } else if (!strcmp(data->devname, "ftdi")) { - rc = dc_serial_ftdi_open(&serial_device, data->context); + rc = dc_context_set_custom_serial(data->context, &serial_ftdi_ops); #endif } if (rc != DC_STATUS_SUCCESS) { report_error(errmsg(rc)); - } else if (serial_device) { - rc = dc_device_custom_open(&data->device, data->context, data->descriptor, serial_device); } else { #else { diff --git a/core/libdivecomputer.h b/core/libdivecomputer.h index f52f6959a..f2894b0c4 100644 --- a/core/libdivecomputer.h +++ b/core/libdivecomputer.h @@ -10,6 +10,7 @@ #include #include #include +#include #include "dive.h" @@ -59,8 +60,11 @@ extern char *logfile_name; extern char *dumpfile_name; #if SSRF_CUSTOM_SERIAL -extern dc_status_t dc_serial_qt_open(dc_serial_t **out, dc_context_t *context, const char *devaddr); -extern dc_status_t dc_serial_ftdi_open(dc_serial_t **out, dc_context_t *context); +// WTF. this symbol never shows up at link time +//extern dc_custom_serial_t qt_serial_ops; +// Thats why I've worked around it with a stupid helper returning it. +dc_custom_serial_t* get_qt_serial_ops(); +extern dc_custom_serial_t serial_ftdi_ops; #endif #ifdef __cplusplus diff --git a/core/qtserialbluetooth.cpp b/core/qtserialbluetooth.cpp index 6b104157a..a7856af64 100644 --- a/core/qtserialbluetooth.cpp +++ b/core/qtserialbluetooth.cpp @@ -19,9 +19,7 @@ #include extern "C" { -typedef struct serial_t { - /* Library context. */ - dc_context_t *context; +typedef struct qt_serial_t { /* * RFCOMM socket used for Bluetooth Serial communication. */ @@ -31,22 +29,16 @@ typedef struct serial_t { QBluetoothSocket *socket; #endif long timeout; -} serial_t; +} qt_serial_t; -static int qt_serial_open(serial_t **out, dc_context_t *context, const char* devaddr) +static dc_status_t qt_serial_open(void **userdata, const char* devaddr) { - if (out == NULL) - return DC_STATUS_INVALIDARGS; - // Allocate memory. - serial_t *serial_port = (serial_t *) malloc (sizeof (serial_t)); + qt_serial_t *serial_port = (qt_serial_t *) malloc (sizeof (qt_serial_t)); if (serial_port == NULL) { return DC_STATUS_NOMEMORY; } - // Library context. - serial_port->context = context; - // Default to blocking reads. serial_port->timeout = -1; @@ -172,17 +164,19 @@ static int qt_serial_open(serial_t **out, dc_context_t *context, const char* dev case QBluetoothSocket::NetworkError: return DC_STATUS_IO; default: - return QBluetoothSocket::UnknownSocketError; + return DC_STATUS_IO; } } #endif - *out = serial_port; + *userdata = serial_port; return DC_STATUS_SUCCESS; } -static int qt_serial_close(serial_t *device) +static dc_status_t qt_serial_close(void **userdata) { + qt_serial_t *device = (qt_serial_t*) *userdata; + if (device == NULL) return DC_STATUS_SUCCESS; @@ -202,36 +196,38 @@ static int qt_serial_close(serial_t *device) free(device); #endif + *userdata = NULL; + return DC_STATUS_SUCCESS; } -static int qt_serial_read(serial_t *device, void* data, unsigned int size) +static dc_status_t qt_serial_read(void **userdata, void* data, size_t size, size_t *actual) { + qt_serial_t *device = (qt_serial_t*) *userdata; + #if defined(Q_OS_WIN) if (device == NULL) return DC_STATUS_INVALIDARGS; - unsigned int nbytes = 0; + size_t nbytes = 0; int rc; while (nbytes < size) { rc = recv (device->socket, (char *) data + nbytes, size - nbytes, 0); if (rc < 0) { - return -1; // Error during recv call. + return DC_STATUS_IO; // Error during recv call. } else if (rc == 0) { break; // EOF reached. } nbytes += rc; } - - return nbytes; #else if (device == NULL || device->socket == NULL) return DC_STATUS_INVALIDARGS; - unsigned int nbytes = 0; + size_t nbytes = 0; int rc; while(nbytes < size && device->socket->state() == QBluetoothSocket::ConnectedState) @@ -242,7 +238,7 @@ static int qt_serial_read(serial_t *device, void* data, unsigned int size) if (errno == EINTR || errno == EAGAIN) continue; // Retry. - return -1; // Something really bad happened :-( + return DC_STATUS_IO; // Something really bad happened :-( } else if (rc == 0) { // Wait until the device is available for read operations QEventLoop loop; @@ -254,23 +250,27 @@ static int qt_serial_read(serial_t *device, void* data, unsigned int size) loop.exec(); if (!timer.isActive()) - return nbytes; + break; } nbytes += rc; } - - return nbytes; #endif + if (actual) + *actual = nbytes; + + return DC_STATUS_SUCCESS; } -static int qt_serial_write(serial_t *device, const void* data, unsigned int size) +static dc_status_t qt_serial_write(void **userdata, const void* data, size_t size, size_t *actual) { + qt_serial_t *device = (qt_serial_t*) *userdata; + #if defined(Q_OS_WIN) if (device == NULL) return DC_STATUS_INVALIDARGS; - unsigned int nbytes = 0; + size_t nbytes = 0; int rc; while (nbytes < size) { @@ -282,13 +282,11 @@ static int qt_serial_write(serial_t *device, const void* data, unsigned int size nbytes += rc; } - - return nbytes; #else if (device == NULL || device->socket == NULL) return DC_STATUS_INVALIDARGS; - unsigned int nbytes = 0; + size_t nbytes = 0; int rc; while(nbytes < size && device->socket->state() == QBluetoothSocket::ConnectedState) @@ -299,20 +297,23 @@ static int qt_serial_write(serial_t *device, const void* data, unsigned int size if (errno == EINTR || errno == EAGAIN) continue; // Retry. - return -1; // Something really bad happened :-( + return DC_STATUS_IO; // Something really bad happened :-( } else if (rc == 0) { break; } nbytes += rc; } - - return nbytes; #endif + if (actual) + *actual = nbytes; + + return DC_STATUS_SUCCESS; } -static int qt_serial_flush(serial_t *device, int queue) +static dc_status_t qt_serial_flush(void **userdata, dc_direction_t queue) { + qt_serial_t *device = (qt_serial_t*) *userdata; (void)queue; if (device == NULL) return DC_STATUS_INVALIDARGS; @@ -325,24 +326,27 @@ static int qt_serial_flush(serial_t *device, int queue) return DC_STATUS_SUCCESS; } -static int qt_serial_get_received(serial_t *device) +static dc_status_t qt_serial_get_received(void **userdata, size_t *available) { + qt_serial_t *device = (qt_serial_t*) *userdata; #if defined(Q_OS_WIN) if (device == NULL) return DC_STATUS_INVALIDARGS; // TODO use WSAIoctl to get the information - return 0; + *available = 0; #else if (device == NULL || device->socket == NULL) return DC_STATUS_INVALIDARGS; - return device->socket->bytesAvailable(); + *available = device->socket->bytesAvailable(); #endif + + return DC_STATUS_SUCCESS; } -static int qt_serial_get_transmitted(serial_t *device) +static int qt_serial_get_transmitted(qt_serial_t *device) { #if defined(Q_OS_WIN) if (device == NULL) @@ -359,8 +363,10 @@ static int qt_serial_get_transmitted(serial_t *device) #endif } -static int qt_serial_set_timeout(serial_t *device, long timeout) +static dc_status_t qt_serial_set_timeout(void **userdata, long timeout) { + qt_serial_t *device = (qt_serial_t*) *userdata; + if (device == NULL) return DC_STATUS_INVALIDARGS; @@ -369,48 +375,27 @@ static int qt_serial_set_timeout(serial_t *device, long timeout) return DC_STATUS_SUCCESS; } - -const dc_serial_operations_t qt_serial_ops = { +dc_custom_serial_t qt_serial_ops = { + .userdata = NULL, .open = qt_serial_open, .close = qt_serial_close, .read = qt_serial_read, .write = qt_serial_write, - .flush = qt_serial_flush, - .get_received = qt_serial_get_received, - .get_transmitted = qt_serial_get_transmitted, - .set_timeout = qt_serial_set_timeout + .purge = qt_serial_flush, + .get_available = qt_serial_get_received, + .set_timeout = qt_serial_set_timeout, +// These doesn't make sense over bluetooth +// NULL means NOP + .configure = NULL, + .set_dtr = NULL, + .set_rts = NULL, + .set_halfduplex = NULL, + .set_break = NULL }; -extern void dc_serial_init (dc_serial_t *serial, void *data, const dc_serial_operations_t *ops); - -dc_status_t dc_serial_qt_open(dc_serial_t **out, dc_context_t *context, const char *devaddr) -{ - 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) { - return DC_STATUS_NOMEMORY; - } - - // Initialize data and function pointers - dc_serial_init(serial_device, NULL, &qt_serial_ops); - - // Open the serial device. - dc_status_t rc = (dc_status_t)qt_serial_open (&serial_device->port, context, devaddr); - if (rc != DC_STATUS_SUCCESS) { - free (serial_device); - return rc; - } - - // Set the type of the device - serial_device->type = DC_TRANSPORT_BLUETOOTH; - - *out = serial_device; - - return DC_STATUS_SUCCESS; +dc_custom_serial_t* get_qt_serial_ops() { + return (dc_custom_serial_t*) &qt_serial_ops; } + } #endif diff --git a/core/serial_ftdi.c b/core/serial_ftdi.c index ff1335171..f982d81c7 100644 --- a/core/serial_ftdi.c +++ b/core/serial_ftdi.c @@ -3,7 +3,7 @@ * * Copyright (C) 2008 Jef Driesen * Copyright (C) 2014 Venkatesh Shukla - * Copyright (C) 2015 Anton Lundin + * Copyright (C) 2015-2016 Anton Lundin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -43,38 +43,11 @@ #define SYSERROR(context, errcode) ; #include - -/* Verbatim copied libdivecomputer enums to support configure */ -typedef enum serial_parity_t { - SERIAL_PARITY_NONE, - SERIAL_PARITY_EVEN, - SERIAL_PARITY_ODD -} serial_parity_t; - -typedef enum serial_flowcontrol_t { - SERIAL_FLOWCONTROL_NONE, - SERIAL_FLOWCONTROL_HARDWARE, - SERIAL_FLOWCONTROL_SOFTWARE -} serial_flowcontrol_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; - -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; +#include #define VID 0x0403 // Vendor ID of FTDI -#define MAX_BACKOFF 500 // Max milliseconds to wait before timing out. - -typedef struct serial_t { +typedef struct ftdi_serial_t { /* Library context. */ dc_context_t *context; /* @@ -95,35 +68,37 @@ typedef struct serial_t { int halfduplex; unsigned int baudrate; unsigned int nbits; -} serial_t; +} ftdi_serial_t; -static int serial_ftdi_get_received (serial_t *device) +static dc_status_t serial_ftdi_get_received (void **userdata, size_t *value) { + ftdi_serial_t *device = (ftdi_serial_t*) *userdata; + if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; // Direct access is not encouraged. But function implementation // is not available. The return quantity might be anything. // Find out further about its possible values and correct way of // access. - int bytes = device->ftdi_ctx->readbuffer_remaining; + *value = device->ftdi_ctx->readbuffer_remaining; - return bytes; + return DC_STATUS_SUCCESS; } -static int serial_ftdi_get_transmitted (serial_t *device) +static dc_status_t serial_ftdi_get_transmitted (ftdi_serial_t *device) { if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; // This is not possible using libftdi. Look further into it. - return -1; + return DC_STATUS_UNSUPPORTED; } -static int serial_ftdi_sleep (serial_t *device, unsigned long timeout) +static dc_status_t serial_ftdi_sleep (ftdi_serial_t *device, unsigned long timeout) { if (device == NULL) - return -1; + return DC_STATUS_INVALIDARGS; INFO (device->context, "Sleep: value=%lu", timeout); @@ -134,11 +109,11 @@ static int serial_ftdi_sleep (serial_t *device, unsigned long timeout) while (nanosleep (&ts, &ts) != 0) { if (errno != EINTR ) { SYSERROR (device->context, errno); - return -1; + return DC_STATUS_IO; } } - return 0; + return DC_STATUS_SUCCESS; } @@ -167,18 +142,10 @@ static int serial_ftdi_open_device (struct ftdi_context *ftdi_ctx) // // Open the serial port. // Initialise ftdi_context and use it to open the device -// -//FIXME: ugly forward declaration of serial_ftdi_configure, util we support configure for real... -static dc_status_t serial_ftdi_configure (serial_t *device, int baudrate, int databits, int parity, int stopbits, int flowcontrol); -static dc_status_t serial_ftdi_open (serial_t **out, dc_context_t *context, const char* name) +static dc_status_t serial_ftdi_open (void **userdata, const char* name) { - if (out == NULL) - return -1; // EINVAL (Invalid argument) - - INFO (context, "Open: name=%s", name ? name : ""); - // Allocate memory. - serial_t *device = (serial_t *) malloc (sizeof (serial_t)); + ftdi_serial_t *device = (ftdi_serial_t *) malloc (sizeof (ftdi_serial_t)); if (device == NULL) { SYSERROR (context, errno); return DC_STATUS_NOMEMORY; @@ -192,7 +159,7 @@ static dc_status_t serial_ftdi_open (serial_t **out, dc_context_t *context, cons } // Library context. - device->context = context; + //device->context = context; // Default to blocking reads. device->timeout = -1; @@ -231,10 +198,7 @@ static dc_status_t serial_ftdi_open (serial_t **out, dc_context_t *context, cons device->ftdi_ctx = ftdi_ctx; - //FIXME: remove this when custom-serial have support for configure calls - serial_ftdi_configure (device, 115200, 8, 0, 1, 0); - - *out = device; + *userdata = device; return DC_STATUS_SUCCESS; } @@ -242,10 +206,12 @@ static dc_status_t serial_ftdi_open (serial_t **out, dc_context_t *context, cons // // Close the serial port. // -static int serial_ftdi_close (serial_t *device) +static dc_status_t serial_ftdi_close (void **userdata) { + ftdi_serial_t *device = (ftdi_serial_t*) *userdata; + if (device == NULL) - return 0; + return DC_STATUS_SUCCESS; // Restore the initial terminal attributes. // See if it is possible using libusb or libftdi @@ -262,16 +228,20 @@ static int serial_ftdi_close (serial_t *device) // Free memory. free (device); - return 0; + *userdata = NULL; + + return DC_STATUS_SUCCESS; } // // Configure the serial port (baudrate, databits, parity, stopbits and flowcontrol). // -static dc_status_t serial_ftdi_configure (serial_t *device, int baudrate, int databits, int parity, int stopbits, int flowcontrol) +static dc_status_t serial_ftdi_configure (void **userdata, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol) { + ftdi_serial_t *device = (ftdi_serial_t*) *userdata; + 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); @@ -282,7 +252,7 @@ static dc_status_t serial_ftdi_configure (serial_t *device, int baudrate, int da if (ftdi_set_baudrate(device->ftdi_ctx, baudrate) < 0) { ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); - return -1; + return DC_STATUS_IO; } // Set the character size. @@ -299,27 +269,30 @@ static dc_status_t serial_ftdi_configure (serial_t *device, int baudrate, int da // Set the parity type. switch (parity) { - case SERIAL_PARITY_NONE: // No parity + case DC_PARITY_NONE: /**< No parity */ ft_parity = NONE; break; - case SERIAL_PARITY_EVEN: // Even parity + case DC_PARITY_EVEN: /**< Even parity */ ft_parity = EVEN; break; - case SERIAL_PARITY_ODD: // Odd parity + case DC_PARITY_ODD: /**< Odd parity */ ft_parity = ODD; break; + case DC_PARITY_MARK: /**< Mark parity (always 1) */ + case DC_PARITY_SPACE: /**< Space parity (alwasy 0) */ default: return DC_STATUS_INVALIDARGS; } // Set the number of stop bits. switch (stopbits) { - case 1: // One stopbit + case DC_STOPBITS_ONE: /**< 1 stop bit */ ft_stopbits = STOP_BIT_1; break; - case 2: // Two stopbits + case DC_STOPBITS_TWO: /**< 2 stop bits */ ft_stopbits = STOP_BIT_2; break; + case DC_STOPBITS_ONEPOINTFIVE: /**< 1.5 stop bits*/ default: return DC_STATUS_INVALIDARGS; } @@ -332,19 +305,19 @@ static dc_status_t serial_ftdi_configure (serial_t *device, int baudrate, int da // Set the flow control. switch (flowcontrol) { - case SERIAL_FLOWCONTROL_NONE: // No flow control. + case DC_FLOWCONTROL_NONE: /**< No flow control */ if (ftdi_setflowctrl(device->ftdi_ctx, SIO_DISABLE_FLOW_CTRL) < 0) { ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); return DC_STATUS_IO; } break; - case SERIAL_FLOWCONTROL_HARDWARE: // Hardware (RTS/CTS) flow control. + case DC_FLOWCONTROL_HARDWARE: /**< Hardware (RTS/CTS) flow control */ if (ftdi_setflowctrl(device->ftdi_ctx, SIO_RTS_CTS_HS) < 0) { ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); return DC_STATUS_IO; } break; - case SERIAL_FLOWCONTROL_SOFTWARE: // Software (XON/XOFF) flow control. + case DC_FLOWCONTROL_SOFTWARE: /**< Software (XON/XOFF) flow control */ if (ftdi_setflowctrl(device->ftdi_ctx, SIO_XON_XOFF_HS) < 0) { ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); return DC_STATUS_IO; @@ -363,86 +336,70 @@ static dc_status_t serial_ftdi_configure (serial_t *device, int baudrate, int da // // Configure the serial port (timeouts). // -static int serial_ftdi_set_timeout (serial_t *device, long timeout) +static dc_status_t serial_ftdi_set_timeout (void **userdata, long timeout) { + ftdi_serial_t *device = (ftdi_serial_t*) *userdata; + if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; INFO (device->context, "Timeout: value=%li", timeout); device->timeout = timeout; - return 0; + return DC_STATUS_SUCCESS; } -static int serial_ftdi_set_halfduplex (serial_t *device, int value) +static dc_status_t serial_ftdi_set_halfduplex (void **userdata, int value) { + ftdi_serial_t *device = (ftdi_serial_t*) *userdata; + if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; // Most ftdi chips support full duplex operation. ft232rl does. // Crosscheck other chips. device->halfduplex = value; - return 0; + return DC_STATUS_SUCCESS; } -static int serial_ftdi_read (serial_t *device, void *data, unsigned int size) +static dc_status_t serial_ftdi_read (void **userdata, void *data, size_t size, size_t *actual) { + ftdi_serial_t *device = (ftdi_serial_t*) *userdata; + if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; // The total timeout. long timeout = device->timeout; - // The absolute target time. - struct timeval tve; + // Simulate blocking read as 10s timeout + if (timeout == -1) + timeout = 10000; - static int backoff = 1; - int init = 1; + int backoff = 1; + int slept = 0; unsigned int nbytes = 0; while (nbytes < size) { - struct timeval tvt; - if (timeout > 0) { - struct timeval now; - if (gettimeofday (&now, NULL) != 0) { - SYSERROR (device->context, errno); - return -1; - } - - if (init) { - // Calculate the initial timeout. - tvt.tv_sec = (timeout / 1000); - tvt.tv_usec = (timeout % 1000) * 1000; - // Calculate the target time. - timeradd (&now, &tvt, &tve); - } else { - // Calculate the remaining timeout. - if (timercmp (&now, &tve, <)) - timersub (&tve, &now, &tvt); - else - timerclear (&tvt); - } - init = 0; - } else if (timeout == 0) { - timerclear (&tvt); - } - int n = ftdi_read_data (device->ftdi_ctx, (char *) data + nbytes, size - nbytes); if (n < 0) { if (n == LIBUSB_ERROR_INTERRUPTED) continue; //Retry. ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); - return -1; //Error during read call. + return DC_STATUS_IO; //Error during read call. } else if (n == 0) { // Exponential backoff. - if (backoff > MAX_BACKOFF) { + if (slept >= timeout) { ERROR(device->context, "%s", "FTDI read timed out."); - return -1; + return DC_STATUS_TIMEOUT; } serial_ftdi_sleep (device, backoff); + slept += backoff; backoff *= 2; + if (backoff + slept > timeout) + backoff = timeout - slept; } else { // Reset backoff to 1 on success. backoff = 1; @@ -453,20 +410,25 @@ static int serial_ftdi_read (serial_t *device, void *data, unsigned int size) INFO (device->context, "Read %d bytes", nbytes); - return nbytes; + if (actual) + *actual = nbytes; + + return DC_STATUS_SUCCESS; } -static int serial_ftdi_write (serial_t *device, const void *data, unsigned int size) +static dc_status_t serial_ftdi_write (void **userdata, const void *data, size_t size, size_t *actual) { + ftdi_serial_t *device = (ftdi_serial_t*) *userdata; + if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; struct timeval tve, tvb; if (device->halfduplex) { // Get the current time. if (gettimeofday (&tvb, NULL) != 0) { SYSERROR (device->context, errno); - return -1; + return DC_STATUS_IO; } } @@ -478,7 +440,7 @@ static int serial_ftdi_write (serial_t *device, const void *data, unsigned int s if (n == LIBUSB_ERROR_INTERRUPTED) continue; // Retry. ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); - return -1; // Error during write call. + return DC_STATUS_IO; // Error during write call. } else if (n == 0) { break; // EOF. } @@ -490,7 +452,7 @@ static int serial_ftdi_write (serial_t *device, const void *data, unsigned int s // Get the current time. if (gettimeofday (&tve, NULL) != 0) { SYSERROR (device->context, errno); - return -1; + return DC_STATUS_IO; } // Calculate the elapsed time (microseconds). @@ -515,46 +477,55 @@ static int serial_ftdi_write (serial_t *device, const void *data, unsigned int s INFO (device->context, "Wrote %d bytes", nbytes); - return nbytes; + if (actual) + *actual = nbytes; + + return DC_STATUS_SUCCESS; } -static int serial_ftdi_flush (serial_t *device, int queue) +static dc_status_t serial_ftdi_flush (void **userdata, dc_direction_t queue) { + ftdi_serial_t *device = (ftdi_serial_t*) *userdata; + if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; - INFO (device->context, "Flush: queue=%u, input=%i, output=%i", queue, - serial_ftdi_get_received (device), + size_t input; + serial_ftdi_get_received (userdata, &input); + INFO (device->context, "Flush: queue=%u, input=%lu, output=%i", queue, input, serial_ftdi_get_transmitted (device)); switch (queue) { - case SERIAL_QUEUE_INPUT: + case DC_DIRECTION_INPUT: /**< Input direction */ if (ftdi_usb_purge_tx_buffer(device->ftdi_ctx)) { ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); - return -1; + return DC_STATUS_IO; } break; - case SERIAL_QUEUE_OUTPUT: + case DC_DIRECTION_OUTPUT: /**< Output direction */ if (ftdi_usb_purge_rx_buffer(device->ftdi_ctx)) { ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); - return -1; + return DC_STATUS_IO; } break; + case DC_DIRECTION_ALL: /**< All directions */ default: if (ftdi_usb_purge_buffers(device->ftdi_ctx)) { ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); - return -1; + return DC_STATUS_IO; } break; } - return 0; + return DC_STATUS_SUCCESS; } -static int serial_ftdi_send_break (serial_t *device) +static dc_status_t serial_ftdi_send_break (void **userdata) { + ftdi_serial_t *device = (ftdi_serial_t*) *userdata; + if (device == NULL) - return -1; // EINVAL (Invalid argument)a + return DC_STATUS_INVALIDARGS; INFO (device->context, "Break : One time period."); @@ -563,103 +534,72 @@ static int serial_ftdi_send_break (serial_t *device) // and resetting the baudrate up again. But it has flaws. // Not implementing it before researching more. - return -1; + return DC_STATUS_UNSUPPORTED; } -static int serial_ftdi_set_break (serial_t *device, int level) +static dc_status_t serial_ftdi_set_break (void **userdata, int level) { + ftdi_serial_t *device = (ftdi_serial_t*) *userdata; + if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; INFO (device->context, "Break: value=%i", level); // Not implemented in libftdi yet. Research it further. - return -1; + return DC_STATUS_UNSUPPORTED; } -static int serial_ftdi_set_dtr (serial_t *device, int level) +static dc_status_t serial_ftdi_set_dtr (void **userdata, int level) { + ftdi_serial_t *device = (ftdi_serial_t*) *userdata; + if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; INFO (device->context, "DTR: value=%i", level); if (ftdi_setdtr(device->ftdi_ctx, level)) { ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); - return -1; + return DC_STATUS_IO; } - return 0; + return DC_STATUS_SUCCESS; } -static int serial_ftdi_set_rts (serial_t *device, int level) +static dc_status_t serial_ftdi_set_rts (void **userdata, int level) { + ftdi_serial_t *device = (ftdi_serial_t*) *userdata; + if (device == NULL) - return -1; // EINVAL (Invalid argument) + return DC_STATUS_INVALIDARGS; INFO (device->context, "RTS: value=%i", level); if (ftdi_setrts(device->ftdi_ctx, level)) { ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); - return -1; + return DC_STATUS_IO; } - return 0; + return DC_STATUS_SUCCESS; } -const dc_serial_operations_t serial_ftdi_ops = { +dc_custom_serial_t serial_ftdi_ops = { + .userdata = NULL, .open = serial_ftdi_open, .close = serial_ftdi_close, .read = serial_ftdi_read, .write = serial_ftdi_write, - .flush = serial_ftdi_flush, - .get_received = serial_ftdi_get_received, - .get_transmitted = NULL, /*NOT USED ANYWHERE! serial_ftdi_get_transmitted */ - .set_timeout = serial_ftdi_set_timeout -#ifdef FIXED_SSRF_CUSTOM_SERIAL - , + .purge = serial_ftdi_flush, + .get_available = serial_ftdi_get_received, + .set_timeout = serial_ftdi_set_timeout, .configure = serial_ftdi_configure, -//static int serial_ftdi_configure (serial_t *device, int baudrate, int databits, int parity, int stopbits, int flowcontrol) - .set_halfduplex = serial_ftdi_set_halfduplex, -//static int serial_ftdi_set_halfduplex (serial_t *device, int value) - .send_break = serial_ftdi_send_break, -//static int serial_ftdi_send_break (serial_t *device) - .set_break = serial_ftdi_set_break, -//static int serial_ftdi_set_break (serial_t *device, int level) .set_dtr = serial_ftdi_set_dtr, -//static int serial_ftdi_set_dtr (serial_t *device, int level) - .set_rts = serial_ftdi_set_rts -//static int serial_ftdi_set_rts (serial_t *device, int level) -#endif + .set_rts = serial_ftdi_set_rts, + .set_halfduplex = serial_ftdi_set_halfduplex, +// Can't be done in ftdi? +// only used in vyper2 +// NULL means NOP + .set_break = NULL }; - -dc_status_t dc_serial_ftdi_open(dc_serial_t **out, dc_context_t *context) -{ - 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) { - return DC_STATUS_NOMEMORY; - } - - // Initialize data and function pointers - dc_serial_init(serial_device, NULL, &serial_ftdi_ops); - - // Open the serial device. - dc_status_t rc = (dc_status_t) serial_ftdi_open (&serial_device->port, context, NULL); - if (rc != DC_STATUS_SUCCESS) { - free (serial_device); - return rc; - } - - // Set the type of the device - serial_device->type = DC_TRANSPORT_USB;; - - *out = serial_device; - - return DC_STATUS_SUCCESS; -} -- cgit v1.2.3-70-g09d2