diff options
author | Tomaz Canabrava <tomaz.canabrava@intel.com> | 2015-09-02 20:52:34 -0300 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2015-10-30 10:36:48 -0700 |
commit | 4c0156e3d51b389db8eccc3fa3da4b8f248f9b13 (patch) | |
tree | 966868d29150fdba13a5a56fb4305bc432ec7a72 /serial_ftdi.c | |
parent | a0798214231c652ac6142228f5ddfc4b65c921f8 (diff) | |
download | subsurface-4c0156e3d51b389db8eccc3fa3da4b8f248f9b13.tar.gz |
Move all core-functionality to subsurface-core
And adapt a new CMakeLists.txt file for it. On the way I've also
found out that we where double-compilling a few files. I've also
set the subsurface-core as a include_path but that was just to
reduce the noise on this commit, since I plan to remove it from
the include path to make it obligatory to specify something like
include "subsurface-core/dive.h"
for the header files. Since the app is growing quite a bit we ended
up having a few different files with almost same name that did
similar things, I want to kill that (for instance Dive.h, dive.h,
PrintDive.h and such).
Signed-off-by: Tomaz Canabrava <tomaz.canabrava@intel.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'serial_ftdi.c')
-rw-r--r-- | serial_ftdi.c | 664 |
1 files changed, 0 insertions, 664 deletions
diff --git a/serial_ftdi.c b/serial_ftdi.c deleted file mode 100644 index cbac026cf..000000000 --- a/serial_ftdi.c +++ /dev/null @@ -1,664 +0,0 @@ -/* - * libdivecomputer - * - * Copyright (C) 2008 Jef Driesen - * Copyright (C) 2014 Venkatesh Shukla - * Copyright (C) 2015 Anton Lundin - * - * 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 <stdlib.h> // malloc, free -#include <string.h> // strerror -#include <errno.h> // errno -#include <sys/time.h> // gettimeofday -#include <time.h> // nanosleep -#include <stdio.h> - -#include <libusb.h> -#include <ftdi.h> - -#ifndef __ANDROID__ -#define INFO(context, fmt, ...) fprintf(stderr, "INFO: " fmt "\n", ##__VA_ARGS__) -#define ERROR(context, fmt, ...) fprintf(stderr, "ERROR: " fmt "\n", ##__VA_ARGS__) -#else -#include <android/log.h> -#define INFO(context, fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, __FILE__, "INFO: " fmt "\n", ##__VA_ARGS__) -#define ERROR(context, fmt, ...) __android_log_print(ANDROID_LOG_DEBUG, __FILE__, "ERROR: " fmt "\n", ##__VA_ARGS__) -#endif -//#define SYSERROR(context, errcode) ERROR(__FILE__ ":" __LINE__ ": %s", strerror(errcode)) -#define SYSERROR(context, errcode) ; - -#include <libdivecomputer/custom_serial.h> - -/* 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; - -#define VID 0x0403 // Vendor ID of FTDI - -#define MAX_BACKOFF 500 // Max milliseconds to wait before timing out. - -typedef struct serial_t { - /* Library context. */ - dc_context_t *context; - /* - * The file descriptor corresponding to the serial port. - * Also a libftdi_ftdi_ctx could be used? - */ - struct ftdi_context *ftdi_ctx; - long timeout; - /* - * Serial port settings are saved into this variable immediately - * after the port is opened. These settings are restored when the - * serial port is closed. - * Saving this using libftdi context or libusb. Search further. - * Custom implementation using libftdi functions could be done. - */ - - /* Half-duplex settings */ - int halfduplex; - unsigned int baudrate; - unsigned int nbits; -} serial_t; - -static int serial_ftdi_get_received (serial_t *device) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument) - - // 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; - - return bytes; -} - -static int serial_ftdi_get_transmitted (serial_t *device) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument) - - // This is not possible using libftdi. Look further into it. - return -1; -} - -static int serial_ftdi_sleep (serial_t *device, unsigned long timeout) -{ - if (device == NULL) - return -1; - - INFO (device->context, "Sleep: value=%lu", 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; - } - } - - return 0; -} - - -// Used internally for opening ftdi devices -static int serial_ftdi_open_device (struct ftdi_context *ftdi_ctx) -{ - int accepted_pids[] = { 0x6001, 0x6010, 0x6011, // Suunto (Smart Interface), Heinrichs Weikamp - 0xF460, // Oceanic - 0xF680, // Suunto - 0x87D0, // Cressi (Leonardo) - }; - int num_accepted_pids = 6; - int i, pid, ret; - for (i = 0; i < num_accepted_pids; i++) { - pid = accepted_pids[i]; - ret = ftdi_usb_open (ftdi_ctx, VID, pid); - if (ret == -3) // Device not found - continue; - else - return ret; - } - // No supported devices are attached. - return ret; -} - -// -// 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) -{ - 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)); - if (device == NULL) { - SYSERROR (context, errno); - return DC_STATUS_NOMEMORY; - } - - struct ftdi_context *ftdi_ctx = ftdi_new(); - if (ftdi_ctx == NULL) { - free(device); - SYSERROR (context, errno); - return DC_STATUS_NOMEMORY; - } - - // Library context. - device->context = context; - - // Default to blocking reads. - device->timeout = -1; - - // Default to full-duplex. - device->halfduplex = 0; - device->baudrate = 0; - device->nbits = 0; - - // Initialize device ftdi context - ftdi_init(ftdi_ctx); - - if (ftdi_set_interface(ftdi_ctx,INTERFACE_ANY)) { - free(device); - ERROR (context, "%s", ftdi_get_error_string(ftdi_ctx)); - return DC_STATUS_IO; - } - - if (serial_ftdi_open_device(ftdi_ctx) < 0) { - free(device); - ERROR (context, "%s", ftdi_get_error_string(ftdi_ctx)); - return DC_STATUS_IO; - } - - if (ftdi_usb_reset(ftdi_ctx)) { - ERROR (context, "%s", ftdi_get_error_string(ftdi_ctx)); - return DC_STATUS_IO; - } - - if (ftdi_usb_purge_buffers(ftdi_ctx)) { - free(device); - ERROR (context, "%s", ftdi_get_error_string(ftdi_ctx)); - return DC_STATUS_IO; - } - - 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; - - return DC_STATUS_SUCCESS; -} - -// -// Close the serial port. -// -static int serial_ftdi_close (serial_t *device) -{ - if (device == NULL) - return 0; - - // Restore the initial terminal attributes. - // See if it is possible using libusb or libftdi - - int ret = ftdi_usb_close(device->ftdi_ctx); - if (ret < 0) { - ERROR (device->context, "Unable to close the ftdi device : %d (%s)\n", - ret, ftdi_get_error_string(device->ftdi_ctx)); - return ret; - } - - ftdi_free(device->ftdi_ctx); - - // Free memory. - free (device); - - return 0; -} - -// -// 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) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument) - - INFO (device->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i", - baudrate, databits, parity, stopbits, flowcontrol); - - enum ftdi_bits_type ft_bits; - enum ftdi_stopbits_type ft_stopbits; - enum ftdi_parity_type ft_parity; - - if (ftdi_set_baudrate(device->ftdi_ctx, baudrate) < 0) { - ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); - return -1; - } - - // Set the character size. - switch (databits) { - case 7: - ft_bits = BITS_7; - break; - case 8: - ft_bits = BITS_8; - break; - default: - return DC_STATUS_INVALIDARGS; - } - - // Set the parity type. - switch (parity) { - case SERIAL_PARITY_NONE: // No parity - ft_parity = NONE; - break; - case SERIAL_PARITY_EVEN: // Even parity - ft_parity = EVEN; - break; - case SERIAL_PARITY_ODD: // Odd parity - ft_parity = ODD; - break; - default: - return DC_STATUS_INVALIDARGS; - } - - // Set the number of stop bits. - switch (stopbits) { - case 1: // One stopbit - ft_stopbits = STOP_BIT_1; - break; - case 2: // Two stopbits - ft_stopbits = STOP_BIT_2; - break; - default: - return DC_STATUS_INVALIDARGS; - } - - // Set the attributes - if (ftdi_set_line_property(device->ftdi_ctx, ft_bits, ft_stopbits, ft_parity)) { - ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); - return DC_STATUS_IO; - } - - // Set the flow control. - switch (flowcontrol) { - case SERIAL_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. - 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. - 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; - } - break; - default: - return DC_STATUS_INVALIDARGS; - } - - device->baudrate = baudrate; - device->nbits = 1 + databits + stopbits + (parity ? 1 : 0); - - return DC_STATUS_SUCCESS; -} - -// -// Configure the serial port (timeouts). -// -static int serial_ftdi_set_timeout (serial_t *device, long timeout) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument) - - INFO (device->context, "Timeout: value=%li", timeout); - - device->timeout = timeout; - - return 0; -} - -static int serial_ftdi_set_halfduplex (serial_t *device, int value) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument) - - // Most ftdi chips support full duplex operation. ft232rl does. - // Crosscheck other chips. - - device->halfduplex = value; - - return 0; -} - -static int serial_ftdi_read (serial_t *device, void *data, unsigned int size) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument) - - // The total timeout. - long timeout = device->timeout; - - // The absolute target time. - struct timeval tve; - - static int backoff = 1; - int init = 1; - 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. - } else if (n == 0) { - // Exponential backoff. - if (backoff > MAX_BACKOFF) { - ERROR(device->context, "%s", "FTDI read timed out."); - return -1; - } - serial_ftdi_sleep (device, backoff); - backoff *= 2; - } else { - // Reset backoff to 1 on success. - backoff = 1; - } - - nbytes += n; - } - - INFO (device->context, "Read %d bytes", nbytes); - - return nbytes; -} - -static int serial_ftdi_write (serial_t *device, const void *data, unsigned int size) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument) - - struct timeval tve, tvb; - if (device->halfduplex) { - // Get the current time. - if (gettimeofday (&tvb, NULL) != 0) { - SYSERROR (device->context, errno); - return -1; - } - } - - unsigned int nbytes = 0; - while (nbytes < size) { - - int n = ftdi_write_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 write call. - } else if (n == 0) { - break; // EOF. - } - - nbytes += n; - } - - if (device->halfduplex) { - // Get the current time. - if (gettimeofday (&tve, NULL) != 0) { - SYSERROR (device->context, errno); - return -1; - } - - // Calculate the elapsed time (microseconds). - struct timeval tvt; - timersub (&tve, &tvb, &tvt); - unsigned long elapsed = tvt.tv_sec * 1000000 + tvt.tv_usec; - - // Calculate the expected duration (microseconds). A 2 millisecond fudge - // factor is added because it improves the success rate significantly. - unsigned long expected = 1000000.0 * device->nbits / device->baudrate * size + 0.5 + 2000; - - // Wait for the remaining time. - if (elapsed < expected) { - unsigned long remaining = expected - elapsed; - - // 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_ftdi_sleep (device, (remaining + 999) / 1000); - } - } - - INFO (device->context, "Wrote %d bytes", nbytes); - - return nbytes; -} - -static int serial_ftdi_flush (serial_t *device, int queue) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument) - - INFO (device->context, "Flush: queue=%u, input=%i, output=%i", queue, - serial_ftdi_get_received (device), - serial_ftdi_get_transmitted (device)); - - switch (queue) { - case SERIAL_QUEUE_INPUT: - if (ftdi_usb_purge_tx_buffer(device->ftdi_ctx)) { - ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); - return -1; - } - break; - case SERIAL_QUEUE_OUTPUT: - if (ftdi_usb_purge_rx_buffer(device->ftdi_ctx)) { - ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); - return -1; - } - break; - default: - if (ftdi_usb_purge_buffers(device->ftdi_ctx)) { - ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); - return -1; - } - break; - } - - return 0; -} - -static int serial_ftdi_send_break (serial_t *device) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument)a - - INFO (device->context, "Break : One time period."); - - // no direct functions for sending break signals in libftdi. - // there is a suggestion to lower the baudrate and sending NUL - // and resetting the baudrate up again. But it has flaws. - // Not implementing it before researching more. - - return -1; -} - -static int serial_ftdi_set_break (serial_t *device, int level) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument) - - INFO (device->context, "Break: value=%i", level); - - // Not implemented in libftdi yet. Research it further. - - return -1; -} - -static int serial_ftdi_set_dtr (serial_t *device, int level) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument) - - 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 0; -} - -static int serial_ftdi_set_rts (serial_t *device, int level) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument) - - 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 0; -} - -const dc_serial_operations_t serial_ftdi_ops = { - .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 - , - .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 -}; - -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; -} |