mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
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 <glance@acc.umu.se> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
3104508247
commit
e2c98def26
2 changed files with 195 additions and 168 deletions
|
@ -260,6 +260,8 @@ endif()
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
set(PLATFORM_SRC android.cpp)
|
set(PLATFORM_SRC android.cpp)
|
||||||
set(SUBSURFACE_TARGET subsurface)
|
set(SUBSURFACE_TARGET subsurface)
|
||||||
|
# To allow us to debug log to logcat
|
||||||
|
set(SUBSURFACE_LINK_LIBRARIES ${SUBSURFACE_LINK_LIBRARIES} -llog)
|
||||||
endif()
|
endif()
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||||
set(SUBSURFACE_TARGET Subsurface)
|
set(SUBSURFACE_TARGET Subsurface)
|
||||||
|
|
361
serial_ftdi.c
361
serial_ftdi.c
|
@ -2,6 +2,8 @@
|
||||||
* libdivecomputer
|
* libdivecomputer
|
||||||
*
|
*
|
||||||
* Copyright (C) 2008 Jef Driesen
|
* 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
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -19,10 +21,6 @@
|
||||||
* MA 02110-1301 USA
|
* MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdlib.h> // malloc, free
|
#include <stdlib.h> // malloc, free
|
||||||
#include <string.h> // strerror
|
#include <string.h> // strerror
|
||||||
#include <errno.h> // errno
|
#include <errno.h> // errno
|
||||||
|
@ -33,20 +31,51 @@
|
||||||
#include <libusb.h>
|
#include <libusb.h>
|
||||||
#include <ftdi.h>
|
#include <ftdi.h>
|
||||||
|
|
||||||
#include "serial.h"
|
#ifndef __ANDROID__
|
||||||
#include "context-private.h"
|
#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) ;
|
||||||
|
|
||||||
#define MODEM_DCD 0b10000000
|
#include <libdivecomputer/custom_serial.h>
|
||||||
#define MODEM_RNG 0b01000000
|
|
||||||
#define MODEM_DSR 0b00100000
|
/* Verbatim copied libdivecomputer enums to support configure */
|
||||||
#define MODEM_CTS 0b00010000
|
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 VID 0x0403 // Vendor ID of FTDI
|
||||||
|
|
||||||
#define MAX_BACKOFF 500 // Max milliseconds to wait before timing out.
|
#define MAX_BACKOFF 500 // Max milliseconds to wait before timing out.
|
||||||
|
|
||||||
struct serial_t {
|
typedef struct serial_t {
|
||||||
/* Library ftdi_ctx. */
|
/* Library context. */
|
||||||
dc_context_t *context;
|
dc_context_t *context;
|
||||||
/*
|
/*
|
||||||
* The file descriptor corresponding to the serial port.
|
* The file descriptor corresponding to the serial port.
|
||||||
|
@ -66,10 +95,55 @@ struct serial_t {
|
||||||
int halfduplex;
|
int halfduplex;
|
||||||
unsigned int baudrate;
|
unsigned int baudrate;
|
||||||
unsigned int nbits;
|
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
|
// 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
|
int accepted_pids[] = { 0x6001, 0x6010, 0x6011, // Suunto (Smart Interface), Heinrichs Weikamp
|
||||||
0xF460, // Oceanic
|
0xF460, // Oceanic
|
||||||
|
@ -90,18 +164,13 @@ int open_ftdi_device (struct ftdi_context *ftdi_ctx)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int serial_enumerate (serial_callback_t callback, void *userdata)
|
|
||||||
{
|
|
||||||
// Unimplemented.
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Open the serial port.
|
// Open the serial port.
|
||||||
// Initialise ftdi_context and use it to open the device
|
// 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)
|
if (out == NULL)
|
||||||
return -1; // EINVAL (Invalid argument)
|
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));
|
serial_t *device = (serial_t *) malloc (sizeof (serial_t));
|
||||||
if (device == NULL) {
|
if (device == NULL) {
|
||||||
SYSERROR (context, errno);
|
SYSERROR (context, errno);
|
||||||
return -1; // ENOMEM (Not enough space)
|
return DC_STATUS_NOMEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ftdi_context *ftdi_ctx = ftdi_new();
|
struct ftdi_context *ftdi_ctx = ftdi_new();
|
||||||
if (ftdi_ctx == NULL) {
|
if (ftdi_ctx == NULL) {
|
||||||
SYSERROR (context, errno);
|
SYSERROR (context, errno);
|
||||||
return -1; // ENOMEM (Not enough space)
|
return DC_STATUS_NOMEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Library context.
|
// Library context.
|
||||||
|
@ -136,35 +205,39 @@ int serial_open (serial_t **out, dc_context_t *context, const char* name)
|
||||||
ftdi_init(ftdi_ctx);
|
ftdi_init(ftdi_ctx);
|
||||||
|
|
||||||
if (ftdi_set_interface(ftdi_ctx,INTERFACE_ANY)) {
|
if (ftdi_set_interface(ftdi_ctx,INTERFACE_ANY)) {
|
||||||
ERROR (context, ftdi_get_error_string(ftdi_ctx));
|
ERROR (context, "%s", ftdi_get_error_string(ftdi_ctx));
|
||||||
return -1;
|
return DC_STATUS_IO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (open_ftdi_device(ftdi_ctx) < 0) {
|
if (serial_ftdi_open_device(ftdi_ctx) < 0) {
|
||||||
ERROR (context, ftdi_get_error_string(ftdi_ctx));
|
ERROR (context, "%s", ftdi_get_error_string(ftdi_ctx));
|
||||||
return -1;
|
return DC_STATUS_IO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ftdi_usb_reset(ftdi_ctx)) {
|
if (ftdi_usb_reset(ftdi_ctx)) {
|
||||||
ERROR (context, ftdi_get_error_string(ftdi_ctx));
|
ERROR (context, "%s", ftdi_get_error_string(ftdi_ctx));
|
||||||
return -1;
|
return DC_STATUS_IO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ftdi_usb_purge_buffers(ftdi_ctx)) {
|
if (ftdi_usb_purge_buffers(ftdi_ctx)) {
|
||||||
ERROR (context, ftdi_get_error_string(ftdi_ctx));
|
ERROR (context, "%s", ftdi_get_error_string(ftdi_ctx));
|
||||||
return -1;
|
return DC_STATUS_IO;
|
||||||
}
|
}
|
||||||
|
|
||||||
device->ftdi_ctx = ftdi_ctx;
|
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;
|
*out = device;
|
||||||
|
|
||||||
return 0;
|
return DC_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Close the serial port.
|
// Close the serial port.
|
||||||
//
|
//
|
||||||
int serial_close (serial_t *device)
|
static int serial_ftdi_close (serial_t *device)
|
||||||
{
|
{
|
||||||
if (device == NULL)
|
if (device == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -190,7 +263,7 @@ int serial_close (serial_t *device)
|
||||||
//
|
//
|
||||||
// Configure the serial port (baudrate, databits, parity, stopbits and flowcontrol).
|
// 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)
|
if (device == NULL)
|
||||||
return -1; // EINVAL (Invalid argument)
|
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;
|
enum ftdi_parity_type ft_parity;
|
||||||
|
|
||||||
if (ftdi_set_baudrate(device->ftdi_ctx, baudrate) < 0) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +289,7 @@ int serial_configure (serial_t *device, int baudrate, int databits, int parity,
|
||||||
ft_bits = BITS_8;
|
ft_bits = BITS_8;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return DC_STATUS_INVALIDARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the parity type.
|
// Set the parity type.
|
||||||
|
@ -231,8 +304,7 @@ int serial_configure (serial_t *device, int baudrate, int databits, int parity,
|
||||||
ft_parity = ODD;
|
ft_parity = ODD;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
return DC_STATUS_INVALIDARGS;
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the number of stop bits.
|
// 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;
|
ft_stopbits = STOP_BIT_2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return DC_STATUS_INVALIDARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the attributes
|
// Set the attributes
|
||||||
if (ftdi_set_line_property(device->ftdi_ctx, ft_bits, ft_stopbits, ft_parity)) {
|
if (ftdi_set_line_property(device->ftdi_ctx, ft_bits, ft_stopbits, ft_parity)) {
|
||||||
ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx));
|
ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx));
|
||||||
return -1;
|
return DC_STATUS_IO;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the flow control.
|
// Set the flow control.
|
||||||
switch (flowcontrol) {
|
switch (flowcontrol) {
|
||||||
case SERIAL_FLOWCONTROL_NONE: // No flow control.
|
case SERIAL_FLOWCONTROL_NONE: // No flow control.
|
||||||
if (ftdi_setflowctrl(device->ftdi_ctx, SIO_DISABLE_FLOW_CTRL) < 0) {
|
if (ftdi_setflowctrl(device->ftdi_ctx, SIO_DISABLE_FLOW_CTRL) < 0) {
|
||||||
ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx));
|
ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx));
|
||||||
return -1;
|
return DC_STATUS_IO;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SERIAL_FLOWCONTROL_HARDWARE: // Hardware (RTS/CTS) flow control.
|
case SERIAL_FLOWCONTROL_HARDWARE: // Hardware (RTS/CTS) flow control.
|
||||||
if (ftdi_setflowctrl(device->ftdi_ctx, SIO_RTS_CTS_HS) < 0) {
|
if (ftdi_setflowctrl(device->ftdi_ctx, SIO_RTS_CTS_HS) < 0) {
|
||||||
ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx));
|
ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx));
|
||||||
return -1;
|
return DC_STATUS_IO;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SERIAL_FLOWCONTROL_SOFTWARE: // Software (XON/XOFF) flow control.
|
case SERIAL_FLOWCONTROL_SOFTWARE: // Software (XON/XOFF) flow control.
|
||||||
if (ftdi_setflowctrl(device->ftdi_ctx, SIO_XON_XOFF_HS) < 0) {
|
if (ftdi_setflowctrl(device->ftdi_ctx, SIO_XON_XOFF_HS) < 0) {
|
||||||
ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx));
|
ERROR (device->context, "%s", ftdi_get_error_string(device->ftdi_ctx));
|
||||||
return -1;
|
return DC_STATUS_IO;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return DC_STATUS_INVALIDARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
device->baudrate = baudrate;
|
device->baudrate = baudrate;
|
||||||
device->nbits = 1 + databits + stopbits + (parity ? 1 : 0);
|
device->nbits = 1 + databits + stopbits + (parity ? 1 : 0);
|
||||||
|
|
||||||
return 0;
|
return DC_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Configure the serial port (timeouts).
|
// 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)
|
if (device == NULL)
|
||||||
return -1; // EINVAL (Invalid argument)
|
return -1; // EINVAL (Invalid argument)
|
||||||
|
@ -298,22 +370,7 @@ int serial_set_timeout (serial_t *device, long timeout)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int serial_ftdi_set_halfduplex (serial_t *device, int value)
|
||||||
//
|
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
if (device == NULL)
|
if (device == NULL)
|
||||||
return -1; // EINVAL (Invalid argument)
|
return -1; // EINVAL (Invalid argument)
|
||||||
|
@ -326,22 +383,7 @@ int serial_set_halfduplex (serial_t *device, int value)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int serial_set_latency (serial_t *device, unsigned int milliseconds)
|
static int serial_ftdi_read (serial_t *device, void *data, unsigned int size)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (device == NULL)
|
if (device == NULL)
|
||||||
return -1; // EINVAL (Invalid argument)
|
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 < 0) {
|
||||||
if (n == LIBUSB_ERROR_INTERRUPTED)
|
if (n == LIBUSB_ERROR_INTERRUPTED)
|
||||||
continue; //Retry.
|
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.
|
return -1; //Error during read call.
|
||||||
} else if (n == 0) {
|
} else if (n == 0) {
|
||||||
// Exponential backoff.
|
// Exponential backoff.
|
||||||
if (backoff > MAX_BACKOFF) {
|
if (backoff > MAX_BACKOFF) {
|
||||||
ERROR(device->context, "FTDI read timed out.");
|
ERROR(device->context, "%s", "FTDI read timed out.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
serial_sleep(device, backoff);
|
serial_ftdi_sleep (device, backoff);
|
||||||
backoff *= 2;
|
backoff *= 2;
|
||||||
} else {
|
} else {
|
||||||
// Reset backoff to 1 on success.
|
// Reset backoff to 1 on success.
|
||||||
|
@ -404,12 +446,12 @@ int serial_read (serial_t *device, void *data, unsigned int size)
|
||||||
nbytes += n;
|
nbytes += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes);
|
INFO (device->context, "Read %d bytes", nbytes);
|
||||||
|
|
||||||
return 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)
|
if (device == NULL)
|
||||||
return -1; // EINVAL (Invalid argument)
|
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 < 0) {
|
||||||
if (n == LIBUSB_ERROR_INTERRUPTED)
|
if (n == LIBUSB_ERROR_INTERRUPTED)
|
||||||
continue; // Retry.
|
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.
|
return -1; // Error during write call.
|
||||||
} else if (n == 0) {
|
} else if (n == 0) {
|
||||||
break; // EOF.
|
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
|
// The remaining time is rounded up to the nearest millisecond to
|
||||||
// match the Windows implementation. The higher resolution is
|
// match the Windows implementation. The higher resolution is
|
||||||
// pointless anyway, since we already added a fudge factor above.
|
// 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;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
int serial_flush (serial_t *device, int queue)
|
static int serial_ftdi_flush (serial_t *device, int queue)
|
||||||
{
|
{
|
||||||
if (device == NULL)
|
if (device == NULL)
|
||||||
return -1; // EINVAL (Invalid argument)
|
return -1; // EINVAL (Invalid argument)
|
||||||
|
|
||||||
INFO (device->context, "Flush: queue=%u, input=%i, output=%i", queue,
|
INFO (device->context, "Flush: queue=%u, input=%i, output=%i", queue,
|
||||||
serial_get_received (device),
|
serial_ftdi_get_received (device),
|
||||||
serial_get_transmitted (device));
|
serial_ftdi_get_transmitted (device));
|
||||||
|
|
||||||
switch (queue) {
|
switch (queue) {
|
||||||
case SERIAL_QUEUE_INPUT:
|
case SERIAL_QUEUE_INPUT:
|
||||||
if (ftdi_usb_purge_tx_buffer(device->ftdi_ctx)) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SERIAL_QUEUE_OUTPUT:
|
case SERIAL_QUEUE_OUTPUT:
|
||||||
if (ftdi_usb_purge_rx_buffer(device->ftdi_ctx)) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (ftdi_usb_purge_buffers(device->ftdi_ctx)) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -504,7 +546,7 @@ int serial_flush (serial_t *device, int queue)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int serial_send_break (serial_t *device)
|
static int serial_ftdi_send_break (serial_t *device)
|
||||||
{
|
{
|
||||||
if (device == NULL)
|
if (device == NULL)
|
||||||
return -1; // EINVAL (Invalid argument)a
|
return -1; // EINVAL (Invalid argument)a
|
||||||
|
@ -519,7 +561,7 @@ int serial_send_break (serial_t *device)
|
||||||
return -1;
|
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)
|
if (device == NULL)
|
||||||
return -1; // EINVAL (Invalid argument)
|
return -1; // EINVAL (Invalid argument)
|
||||||
|
@ -531,7 +573,7 @@ int serial_set_break (serial_t *device, int level)
|
||||||
return -1;
|
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)
|
if (device == NULL)
|
||||||
return -1; // EINVAL (Invalid argument)
|
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);
|
INFO (device->context, "DTR: value=%i", level);
|
||||||
|
|
||||||
if (ftdi_setdtr(device->ftdi_ctx, 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 -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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)
|
if (device == NULL)
|
||||||
return -1; // EINVAL (Invalid argument)
|
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);
|
INFO (device->context, "RTS: value=%i", level);
|
||||||
|
|
||||||
if (ftdi_setrts(device->ftdi_ctx, 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 -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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)
|
if (out == NULL)
|
||||||
return -1; // EINVAL (Invalid argument)
|
return DC_STATUS_INVALIDARGS;
|
||||||
|
|
||||||
// Direct access is not encouraged. But function implementation
|
// Allocate memory.
|
||||||
// is not available. The return quantity might be anything.
|
dc_serial_t *serial_device = (dc_serial_t *) malloc (sizeof (dc_serial_t));
|
||||||
// Find out further about its possible values and correct way of
|
|
||||||
// access.
|
|
||||||
int bytes = device->ftdi_ctx->readbuffer_remaining;
|
|
||||||
|
|
||||||
return bytes;
|
if (serial_device == NULL) {
|
||||||
}
|
return DC_STATUS_NOMEMORY;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (line) {
|
// Initialize data and function pointers
|
||||||
case SERIAL_LINE_DCD:
|
dc_serial_init(serial_device, NULL, &serial_ftdi_ops);
|
||||||
return (status[0] & MODEM_DCD) == MODEM_DCD;
|
|
||||||
case SERIAL_LINE_CTS:
|
// Open the serial device.
|
||||||
return (status[0] & MODEM_CTS) == MODEM_CTS;
|
dc_status_t rc = (dc_status_t) serial_ftdi_open (&serial_device->port, context, NULL);
|
||||||
case SERIAL_LINE_DSR:
|
if (rc != DC_STATUS_SUCCESS) {
|
||||||
return (status[0] & MODEM_DSR) == MODEM_DSR;
|
free (serial_device);
|
||||||
case SERIAL_LINE_RNG:
|
return rc;
|
||||||
return (status[0] & MODEM_RNG) == MODEM_RNG;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
// Set the type of the device
|
||||||
}
|
serial_device->type = DC_TRANSPORT_USB;;
|
||||||
|
|
||||||
int serial_sleep (serial_t *device, unsigned long timeout)
|
*out = serial_device;
|
||||||
{
|
|
||||||
if (device == NULL)
|
return DC_STATUS_SUCCESS;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue