From e2c98def2699c6ed4b98633f780ef3faaf903335 Mon Sep 17 00:00:00 2001 From: Anton Lundin Date: Fri, 21 Aug 2015 00:19:44 +0200 Subject: [PATCH] Turn serial_ftdi.c into a custom_serial This cleans up serial_ftdi.c from being a libdivecomputer source and making it into a subsurface custom_serial. Signed-off-by: Anton Lundin Signed-off-by: Dirk Hohndel --- CMakeLists.txt | 2 + serial_ftdi.c | 361 ++++++++++++++++++++++++++----------------------- 2 files changed, 195 insertions(+), 168 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index deec8b397..92f9e94b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -260,6 +260,8 @@ endif() if(ANDROID) set(PLATFORM_SRC android.cpp) set(SUBSURFACE_TARGET subsurface) + # To allow us to debug log to logcat + set(SUBSURFACE_LINK_LIBRARIES ${SUBSURFACE_LINK_LIBRARIES} -llog) endif() if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") set(SUBSURFACE_TARGET Subsurface) diff --git a/serial_ftdi.c b/serial_ftdi.c index 065cc88cc..ab74b9ac1 100644 --- a/serial_ftdi.c +++ b/serial_ftdi.c @@ -2,6 +2,8 @@ * 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 @@ -19,10 +21,6 @@ * MA 02110-1301 USA */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - #include // malloc, free #include // strerror #include // errno @@ -33,20 +31,51 @@ #include #include -#include "serial.h" -#include "context-private.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 +#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) ; -#define MODEM_DCD 0b10000000 -#define MODEM_RNG 0b01000000 -#define MODEM_DSR 0b00100000 -#define MODEM_CTS 0b00010000 +#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; #define VID 0x0403 // Vendor ID of FTDI #define MAX_BACKOFF 500 // Max milliseconds to wait before timing out. -struct serial_t { - /* Library ftdi_ctx. */ +typedef struct serial_t { + /* Library context. */ dc_context_t *context; /* * The file descriptor corresponding to the serial port. @@ -66,10 +95,55 @@ struct serial_t { 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 -int open_ftdi_device (struct ftdi_context *ftdi_ctx) +static int serial_ftdi_open_device (struct ftdi_context *ftdi_ctx) { int accepted_pids[] = { 0x6001, 0x6010, 0x6011, // Suunto (Smart Interface), Heinrichs Weikamp 0xF460, // Oceanic @@ -90,18 +164,13 @@ int open_ftdi_device (struct ftdi_context *ftdi_ctx) return ret; } -int serial_enumerate (serial_callback_t callback, void *userdata) -{ - // Unimplemented. - return -1; -} - - // // Open the serial port. // Initialise ftdi_context and use it to open the device // -int serial_open (serial_t **out, dc_context_t *context, const char* name) +//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) @@ -112,13 +181,13 @@ int serial_open (serial_t **out, dc_context_t *context, const char* name) serial_t *device = (serial_t *) malloc (sizeof (serial_t)); if (device == NULL) { SYSERROR (context, errno); - return -1; // ENOMEM (Not enough space) + return DC_STATUS_NOMEMORY; } struct ftdi_context *ftdi_ctx = ftdi_new(); if (ftdi_ctx == NULL) { SYSERROR (context, errno); - return -1; // ENOMEM (Not enough space) + return DC_STATUS_NOMEMORY; } // Library context. @@ -136,35 +205,39 @@ int serial_open (serial_t **out, dc_context_t *context, const char* name) ftdi_init(ftdi_ctx); if (ftdi_set_interface(ftdi_ctx,INTERFACE_ANY)) { - ERROR (context, ftdi_get_error_string(ftdi_ctx)); - return -1; + ERROR (context, "%s", ftdi_get_error_string(ftdi_ctx)); + return DC_STATUS_IO; } - if (open_ftdi_device(ftdi_ctx) < 0) { - ERROR (context, ftdi_get_error_string(ftdi_ctx)); - return -1; + if (serial_ftdi_open_device(ftdi_ctx) < 0) { + ERROR (context, "%s", ftdi_get_error_string(ftdi_ctx)); + return DC_STATUS_IO; } if (ftdi_usb_reset(ftdi_ctx)) { - ERROR (context, ftdi_get_error_string(ftdi_ctx)); - return -1; + ERROR (context, "%s", ftdi_get_error_string(ftdi_ctx)); + return DC_STATUS_IO; } if (ftdi_usb_purge_buffers(ftdi_ctx)) { - ERROR (context, ftdi_get_error_string(ftdi_ctx)); - return -1; + 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 0; + return DC_STATUS_SUCCESS; } // // Close the serial port. // -int serial_close (serial_t *device) +static int serial_ftdi_close (serial_t *device) { if (device == NULL) return 0; @@ -190,7 +263,7 @@ int serial_close (serial_t *device) // // 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) +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) @@ -203,7 +276,7 @@ int serial_configure (serial_t *device, int baudrate, int databits, int parity, enum ftdi_parity_type ft_parity; if (ftdi_set_baudrate(device->ftdi_ctx, baudrate) < 0) { - ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); + ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); return -1; } @@ -216,7 +289,7 @@ int serial_configure (serial_t *device, int baudrate, int databits, int parity, ft_bits = BITS_8; break; default: - return -1; + return DC_STATUS_INVALIDARGS; } // Set the parity type. @@ -231,8 +304,7 @@ int serial_configure (serial_t *device, int baudrate, int databits, int parity, ft_parity = ODD; break; default: - - return -1; + return DC_STATUS_INVALIDARGS; } // Set the number of stop bits. @@ -244,49 +316,49 @@ int serial_configure (serial_t *device, int baudrate, int databits, int parity, ft_stopbits = STOP_BIT_2; break; default: - return -1; + return DC_STATUS_INVALIDARGS; } // Set the attributes if (ftdi_set_line_property(device->ftdi_ctx, ft_bits, ft_stopbits, ft_parity)) { - ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); - return -1; + 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, ftdi_get_error_string(device->ftdi_ctx)); - return -1; + 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, ftdi_get_error_string(device->ftdi_ctx)); - return -1; + 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, ftdi_get_error_string(device->ftdi_ctx)); - return -1; + ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); + return DC_STATUS_IO; } break; default: - return -1; + return DC_STATUS_INVALIDARGS; } 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) +static int serial_ftdi_set_timeout (serial_t *device, long timeout) { if (device == NULL) return -1; // EINVAL (Invalid argument) @@ -298,22 +370,7 @@ int serial_set_timeout (serial_t *device, long timeout) return 0; } - -// -// 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) -{ - if (device == NULL) - return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) - - ftdi_read_data_set_chunksize(device->ftdi_ctx, output); - ftdi_write_data_set_chunksize(device->ftdi_ctx, input); - - return 0; -} - -int serial_set_halfduplex (serial_t *device, int value) +static int serial_ftdi_set_halfduplex (serial_t *device, int value) { if (device == NULL) return -1; // EINVAL (Invalid argument) @@ -326,22 +383,7 @@ int serial_set_halfduplex (serial_t *device, int value) return 0; } -int serial_set_latency (serial_t *device, unsigned int milliseconds) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument) - - // Default for ftdi device is 16ms and can be set in the range - // 1 - 255 ms with 1ms least count. - - if (milliseconds < 1 || milliseconds > 255) - return -1; - ftdi_set_latency_timer(device->ftdi_ctx, milliseconds); - - return 0; -} - -int serial_read (serial_t *device, void *data, unsigned int size) +static int serial_ftdi_read (serial_t *device, void *data, unsigned int size) { if (device == NULL) return -1; // EINVAL (Invalid argument) @@ -386,15 +428,15 @@ int serial_read (serial_t *device, void *data, unsigned int size) if (n < 0) { if (n == LIBUSB_ERROR_INTERRUPTED) continue; //Retry. - ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); + 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, "FTDI read timed out."); + ERROR(device->context, "%s", "FTDI read timed out."); return -1; } - serial_sleep(device, backoff); + serial_ftdi_sleep (device, backoff); backoff *= 2; } else { // Reset backoff to 1 on success. @@ -404,12 +446,12 @@ int serial_read (serial_t *device, void *data, unsigned int size) nbytes += n; } - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes); + INFO (device->context, "Read %d bytes", nbytes); return nbytes; } -int serial_write (serial_t *device, const void *data, unsigned int size) +static int serial_ftdi_write (serial_t *device, const void *data, unsigned int size) { if (device == NULL) return -1; // EINVAL (Invalid argument) @@ -430,7 +472,7 @@ int serial_write (serial_t *device, const void *data, unsigned int size) if (n < 0) { if (n == LIBUSB_ERROR_INTERRUPTED) continue; // Retry. - ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); + ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); return -1; // Error during write call. } else if (n == 0) { break; // EOF. @@ -462,40 +504,40 @@ int 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); + serial_ftdi_sleep (device, (remaining + 999) / 1000); } } - HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes); + INFO (device->context, "Wrote %d bytes", nbytes); return nbytes; } -int serial_flush (serial_t *device, int queue) +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_get_received (device), - serial_get_transmitted (device)); + 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, ftdi_get_error_string(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, ftdi_get_error_string(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, ftdi_get_error_string(device->ftdi_ctx)); + ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); return -1; } break; @@ -504,7 +546,7 @@ int serial_flush (serial_t *device, int queue) return 0; } -int serial_send_break (serial_t *device) +static int serial_ftdi_send_break (serial_t *device) { if (device == NULL) return -1; // EINVAL (Invalid argument)a @@ -519,7 +561,7 @@ int serial_send_break (serial_t *device) return -1; } -int serial_set_break (serial_t *device, int level) +static int serial_ftdi_set_break (serial_t *device, int level) { if (device == NULL) return -1; // EINVAL (Invalid argument) @@ -531,7 +573,7 @@ int serial_set_break (serial_t *device, int level) return -1; } -int serial_set_dtr (serial_t *device, int level) +static int serial_ftdi_set_dtr (serial_t *device, int level) { if (device == NULL) return -1; // EINVAL (Invalid argument) @@ -539,14 +581,14 @@ int serial_set_dtr (serial_t *device, int level) INFO (device->context, "DTR: value=%i", level); if (ftdi_setdtr(device->ftdi_ctx, level)) { - ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); + ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); return -1; } return 0; } -int serial_set_rts (serial_t *device, int level) +static int serial_ftdi_set_rts (serial_t *device, int level) { if (device == NULL) return -1; // EINVAL (Invalid argument) @@ -554,82 +596,65 @@ int serial_set_rts (serial_t *device, int level) INFO (device->context, "RTS: value=%i", level); if (ftdi_setrts(device->ftdi_ctx, level)) { - ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); + ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx)); return -1; } return 0; } -int serial_get_received (serial_t *device) +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 (device == NULL) - return -1; // EINVAL (Invalid argument) + if (out == NULL) + 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; + // Allocate memory. + dc_serial_t *serial_device = (dc_serial_t *) malloc (sizeof (dc_serial_t)); - return bytes; -} - -int serial_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; -} - -int serial_get_line (serial_t *device, int line) -{ - if (device == NULL) - return -1; // EINVAL (Invalid argument) - - unsigned short int status[2] = {0}; - - if(ftdi_poll_modem_status(device->ftdi_ctx, status)) { - ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); - return -1; + if (serial_device == NULL) { + return DC_STATUS_NOMEMORY; } - switch (line) { - case SERIAL_LINE_DCD: - return (status[0] & MODEM_DCD) == MODEM_DCD; - case SERIAL_LINE_CTS: - return (status[0] & MODEM_CTS) == MODEM_CTS; - case SERIAL_LINE_DSR: - return (status[0] & MODEM_DSR) == MODEM_DSR; - case SERIAL_LINE_RNG: - return (status[0] & MODEM_RNG) == MODEM_RNG; - default: - return -1; + // 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; } - return 0; -} - -int serial_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; + // Set the type of the device + serial_device->type = DC_TRANSPORT_USB;; + + *out = serial_device; + + return DC_STATUS_SUCCESS; }