Re-indent and style up serial ftdi

Signed-off-by: Anton Lundin <glance@acc.umu.se>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
Anton Lundin 2015-08-21 00:19:43 +02:00 committed by Dirk Hohndel
parent f33843ed35
commit 3104508247

View file

@ -46,31 +46,30 @@
#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 { struct serial_t {
/* Library ftdi_ctx. */ /* Library ftdi_ctx. */
dc_context_t *context; dc_context_t *context;
/* /*
* The file descriptor corresponding to the serial port. * The file descriptor corresponding to the serial port.
* Also a libftdi_ftdi_ctx could be used? * Also a libftdi_ftdi_ctx could be used?
*/ */
struct ftdi_context *ftdi_ctx; struct ftdi_context *ftdi_ctx;
long timeout; long timeout;
/* /*
* Serial port settings are saved into this variable immediately * Serial port settings are saved into this variable immediately
* after the port is opened. These settings are restored when the * after the port is opened. These settings are restored when the
* serial port is closed. * serial port is closed.
* Saving this using libftdi context or libusb. Search further. * Saving this using libftdi context or libusb. Search further.
* Custom implementation using libftdi functions could be done. * Custom implementation using libftdi functions could be done.
*/ */
/* Half-duplex settings */ /* Half-duplex settings */
int halfduplex; int halfduplex;
unsigned int baudrate; unsigned int baudrate;
unsigned int nbits; unsigned int nbits;
}; };
// Used internally for opening ftdi devices // Used internally for opening ftdi devices
int int open_ftdi_device (struct ftdi_context *ftdi_ctx)
open_ftdi_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
@ -91,11 +90,10 @@ open_ftdi_device (struct ftdi_context *ftdi_ctx)
return ret; return ret;
} }
int int serial_enumerate (serial_callback_t callback, void *userdata)
serial_enumerate (serial_callback_t callback, void *userdata)
{ {
// Unimplemented. // Unimplemented.
return -1; return -1;
} }
@ -103,21 +101,19 @@ serial_enumerate (serial_callback_t callback, void *userdata)
// 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)
int
serial_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)
INFO (context, "Open: name=%s", name ? name : ""); INFO (context, "Open: name=%s", name ? name : "");
// Allocate memory. // Allocate memory.
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 -1; // ENOMEM (Not enough space)
} }
struct ftdi_context *ftdi_ctx = ftdi_new(); struct ftdi_context *ftdi_ctx = ftdi_new();
if (ftdi_ctx == NULL) { if (ftdi_ctx == NULL) {
@ -125,223 +121,212 @@ serial_open (serial_t **out, dc_context_t *context, const char* name)
return -1; // ENOMEM (Not enough space) return -1; // ENOMEM (Not enough space)
} }
// Library context. // Library context.
device->context = context; device->context = context;
// Default to blocking reads. // Default to blocking reads.
device->timeout = -1; device->timeout = -1;
// Default to full-duplex. // Default to full-duplex.
device->halfduplex = 0; device->halfduplex = 0;
device->baudrate = 0; device->baudrate = 0;
device->nbits = 0; device->nbits = 0;
// Initialize device ftdi context // Initialize device ftdi context
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, ftdi_get_error_string(ftdi_ctx));
return -1; return -1;
} }
if (open_ftdi_device(ftdi_ctx) < 0) { if (open_ftdi_device(ftdi_ctx) < 0) {
ERROR (context, ftdi_get_error_string(ftdi_ctx)); ERROR (context, ftdi_get_error_string(ftdi_ctx));
return -1;
}
if (ftdi_usb_reset(ftdi_ctx)) {
ERROR (context, ftdi_get_error_string(ftdi_ctx));
return -1; return -1;
} }
if (ftdi_usb_purge_buffers(ftdi_ctx)) { if (ftdi_usb_reset(ftdi_ctx)) {
ERROR (context, ftdi_get_error_string(ftdi_ctx)); ERROR (context, ftdi_get_error_string(ftdi_ctx));
return -1;
}
if (ftdi_usb_purge_buffers(ftdi_ctx)) {
ERROR (context, ftdi_get_error_string(ftdi_ctx));
return -1; return -1;
} }
device->ftdi_ctx = ftdi_ctx; device->ftdi_ctx = ftdi_ctx;
*out = device; *out = device;
return 0; return 0;
} }
// //
// Close the serial port. // Close the serial port.
// //
int serial_close (serial_t *device)
int
serial_close (serial_t *device)
{ {
if (device == NULL) if (device == NULL)
return 0; return 0;
// Restore the initial terminal attributes. // Restore the initial terminal attributes.
// See if it is possible using libusb or libftdi // See if it is possible using libusb or libftdi
int ret = ftdi_usb_close(device->ftdi_ctx); int ret = ftdi_usb_close(device->ftdi_ctx);
if (ret < 0) { if (ret < 0) {
ERROR (device->context, "Unable to close the ftdi device : %d (%s)\n", ERROR (device->context, "Unable to close the ftdi device : %d (%s)\n",
ret, ftdi_get_error_string(device->ftdi_ctx)); ret, ftdi_get_error_string(device->ftdi_ctx));
return ret; return ret;
} }
ftdi_free(device->ftdi_ctx); ftdi_free(device->ftdi_ctx);
// Free memory. // Free memory.
free (device); free (device);
return 0; return 0;
} }
// //
// 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)
int
serial_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)
INFO (device->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i", INFO (device->context, "Configure: baudrate=%i, databits=%i, parity=%i, stopbits=%i, flowcontrol=%i",
baudrate, databits, parity, stopbits, flowcontrol); baudrate, databits, parity, stopbits, flowcontrol);
enum ftdi_bits_type ft_bits; enum ftdi_bits_type ft_bits;
enum ftdi_stopbits_type ft_stopbits; enum ftdi_stopbits_type ft_stopbits;
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, ftdi_get_error_string(device->ftdi_ctx));
return -1; return -1;
} }
// Set the character size. // Set the character size.
switch (databits) { switch (databits) {
case 7: case 7:
ft_bits = BITS_7; ft_bits = BITS_7;
break; break;
case 8: case 8:
ft_bits = BITS_8; ft_bits = BITS_8;
break; break;
default: default:
return -1; return -1;
} }
// Set the parity type. // Set the parity type.
switch (parity) { switch (parity) {
case SERIAL_PARITY_NONE: // No parity case SERIAL_PARITY_NONE: // No parity
ft_parity = NONE; ft_parity = NONE;
break; break;
case SERIAL_PARITY_EVEN: // Even parity case SERIAL_PARITY_EVEN: // Even parity
ft_parity = EVEN; ft_parity = EVEN;
break; break;
case SERIAL_PARITY_ODD: // Odd parity case SERIAL_PARITY_ODD: // Odd parity
ft_parity = ODD; ft_parity = ODD;
break; break;
default: default:
return -1; return -1;
} }
// Set the number of stop bits. // Set the number of stop bits.
switch (stopbits) { switch (stopbits) {
case 1: // One stopbit case 1: // One stopbit
ft_stopbits = STOP_BIT_1; ft_stopbits = STOP_BIT_1;
break; break;
case 2: // Two stopbits case 2: // Two stopbits
ft_stopbits = STOP_BIT_2; ft_stopbits = STOP_BIT_2;
break; break;
default: default:
return -1; return -1;
} }
// 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, ftdi_get_error_string(device->ftdi_ctx));
return -1; return -1;
} }
// 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));
return -1;
}
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)); ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx));
return -1; return -1;
} }
break; break;
case SERIAL_FLOWCONTROL_SOFTWARE: // Software (XON/XOFF) flow control. case SERIAL_FLOWCONTROL_HARDWARE: // Hardware (RTS/CTS) flow control.
if (ftdi_setflowctrl(device->ftdi_ctx, SIO_XON_XOFF_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, ftdi_get_error_string(device->ftdi_ctx));
return -1; return -1;
} }
break; break;
default: case SERIAL_FLOWCONTROL_SOFTWARE: // Software (XON/XOFF) flow control.
return -1; if (ftdi_setflowctrl(device->ftdi_ctx, SIO_XON_XOFF_HS) < 0) {
} ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx));
return -1;
}
break;
default:
return -1;
}
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 0;
} }
// //
// Configure the serial port (timeouts). // Configure the serial port (timeouts).
// //
int serial_set_timeout (serial_t *device, long timeout)
int
serial_set_timeout (serial_t *device, long timeout)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return -1; // EINVAL (Invalid argument)
INFO (device->context, "Timeout: value=%li", timeout); INFO (device->context, "Timeout: value=%li", timeout);
device->timeout = timeout; device->timeout = timeout;
return 0; return 0;
} }
// //
// Configure the serial port (recommended size of the input/output buffers). // 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)
int
serial_set_queue_size (serial_t *device, unsigned int input, unsigned int output)
{ {
if (device == NULL) if (device == NULL)
return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect) return -1; // ERROR_INVALID_PARAMETER (The parameter is incorrect)
ftdi_read_data_set_chunksize(device->ftdi_ctx, output); ftdi_read_data_set_chunksize(device->ftdi_ctx, output);
ftdi_write_data_set_chunksize(device->ftdi_ctx, input); ftdi_write_data_set_chunksize(device->ftdi_ctx, input);
return 0; return 0;
} }
int serial_set_halfduplex (serial_t *device, int value)
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)
// Most ftdi chips support full duplex operation. ft232rl does. // Most ftdi chips support full duplex operation. ft232rl does.
// Crosscheck other chips. // Crosscheck other chips.
device->halfduplex = value; device->halfduplex = value;
return 0; return 0;
} }
int int serial_set_latency (serial_t *device, unsigned int milliseconds)
serial_set_latency (serial_t *device, unsigned int milliseconds)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return -1; // EINVAL (Invalid argument)
@ -351,60 +336,59 @@ serial_set_latency (serial_t *device, unsigned int milliseconds)
if (milliseconds < 1 || milliseconds > 255) if (milliseconds < 1 || milliseconds > 255)
return -1; return -1;
ftdi_set_latency_timer(device->ftdi_ctx, milliseconds); ftdi_set_latency_timer(device->ftdi_ctx, milliseconds);
return 0; return 0;
} }
int int serial_read (serial_t *device, void *data, unsigned int size)
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)
// The total timeout. // The total timeout.
long timeout = device->timeout; long timeout = device->timeout;
// The absolute target time. // The absolute target time.
struct timeval tve; struct timeval tve;
static int backoff = 1; static int backoff = 1;
int init = 1; int init = 1;
unsigned int nbytes = 0; unsigned int nbytes = 0;
while (nbytes < size) { while (nbytes < size) {
struct timeval tvt; struct timeval tvt;
if (timeout > 0) { if (timeout > 0) {
struct timeval now; struct timeval now;
if (gettimeofday (&now, NULL) != 0) { if (gettimeofday (&now, NULL) != 0) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return -1;
} }
if (init) { if (init) {
// Calculate the initial timeout. // Calculate the initial timeout.
tvt.tv_sec = (timeout / 1000); tvt.tv_sec = (timeout / 1000);
tvt.tv_usec = (timeout % 1000) * 1000; tvt.tv_usec = (timeout % 1000) * 1000;
// Calculate the target time. // Calculate the target time.
timeradd (&now, &tvt, &tve); timeradd (&now, &tvt, &tve);
} else { } else {
// Calculate the remaining timeout. // Calculate the remaining timeout.
if (timercmp (&now, &tve, <)) if (timercmp (&now, &tve, <))
timersub (&tve, &now, &tvt); timersub (&tve, &now, &tvt);
else else
timerclear (&tvt); timerclear (&tvt);
} }
init = 0; init = 0;
} else if (timeout == 0) { } else if (timeout == 0) {
timerclear (&tvt); timerclear (&tvt);
} }
int n = ftdi_read_data (device->ftdi_ctx, (char *) data + nbytes, size - nbytes); int n = ftdi_read_data (device->ftdi_ctx, (char *) data + nbytes, size - nbytes);
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, 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, "FTDI read timed out.");
@ -417,119 +401,113 @@ serial_read (serial_t *device, void *data, unsigned int size)
backoff = 1; backoff = 1;
} }
nbytes += n; nbytes += n;
} }
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes); HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Read", (unsigned char *) data, nbytes);
return nbytes; return nbytes;
} }
int serial_write (serial_t *device, const void *data, unsigned int size)
int
serial_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)
struct timeval tve, tvb; struct timeval tve, tvb;
if (device->halfduplex) { if (device->halfduplex) {
// Get the current time. // Get the current time.
if (gettimeofday (&tvb, NULL) != 0) { if (gettimeofday (&tvb, NULL) != 0) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return -1;
} }
} }
unsigned int nbytes = 0; unsigned int nbytes = 0;
while (nbytes < size) { while (nbytes < size) {
int n = ftdi_write_data (device->ftdi_ctx, (char *) data + nbytes, size - nbytes); int n = ftdi_write_data (device->ftdi_ctx, (char *) data + nbytes, size - nbytes);
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, 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.
} }
nbytes += n; nbytes += n;
} }
if (device->halfduplex) { if (device->halfduplex) {
// Get the current time. // Get the current time.
if (gettimeofday (&tve, NULL) != 0) { if (gettimeofday (&tve, NULL) != 0) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return -1;
} }
// Calculate the elapsed time (microseconds). // Calculate the elapsed time (microseconds).
struct timeval tvt; struct timeval tvt;
timersub (&tve, &tvb, &tvt); timersub (&tve, &tvb, &tvt);
unsigned long elapsed = tvt.tv_sec * 1000000 + tvt.tv_usec; unsigned long elapsed = tvt.tv_sec * 1000000 + tvt.tv_usec;
// Calculate the expected duration (microseconds). A 2 millisecond fudge // Calculate the expected duration (microseconds). A 2 millisecond fudge
// factor is added because it improves the success rate significantly. // factor is added because it improves the success rate significantly.
unsigned long expected = 1000000.0 * device->nbits / device->baudrate * size + 0.5 + 2000; unsigned long expected = 1000000.0 * device->nbits / device->baudrate * size + 0.5 + 2000;
// Wait for the remaining time. // Wait for the remaining time.
if (elapsed < expected) { if (elapsed < expected) {
unsigned long remaining = expected - elapsed; unsigned long remaining = expected - elapsed;
// 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_sleep (device, (remaining + 999) / 1000);
} }
} }
HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes); HEXDUMP (device->context, DC_LOGLEVEL_INFO, "Write", (unsigned char *) data, nbytes);
return nbytes; return nbytes;
} }
int serial_flush (serial_t *device, int queue)
int
serial_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_get_received (device),
serial_get_transmitted (device)); serial_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, 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, 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, ftdi_get_error_string(device->ftdi_ctx));
return -1; return -1;
} }
break; break;
} }
return 0; return 0;
} }
int serial_send_break (serial_t *device)
int
serial_send_break (serial_t *device)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument)a return -1; // EINVAL (Invalid argument)a
INFO (device->context, "Break : One time period."); INFO (device->context, "Break : One time period.");
@ -538,133 +516,119 @@ serial_send_break (serial_t *device)
// and resetting the baudrate up again. But it has flaws. // and resetting the baudrate up again. But it has flaws.
// Not implementing it before researching more. // Not implementing it before researching more.
return -1; return -1;
} }
int serial_set_break (serial_t *device, int level)
int
serial_set_break (serial_t *device, int level)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return -1; // EINVAL (Invalid argument)
INFO (device->context, "Break: value=%i", level); INFO (device->context, "Break: value=%i", level);
// Not implemented in libftdi yet. Research it further. // Not implemented in libftdi yet. Research it further.
return -1; return -1;
} }
int serial_set_dtr (serial_t *device, int level)
int
serial_set_dtr (serial_t *device, int level)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return -1; // EINVAL (Invalid argument)
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, ftdi_get_error_string(device->ftdi_ctx));
return -1; return -1;
} }
return 0; return 0;
} }
int serial_set_rts (serial_t *device, int level)
int
serial_set_rts (serial_t *device, int level)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return -1; // EINVAL (Invalid argument)
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, ftdi_get_error_string(device->ftdi_ctx));
return -1; return -1;
} }
return 0; return 0;
} }
int serial_get_received (serial_t *device)
int
serial_get_received (serial_t *device)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return -1; // EINVAL (Invalid argument)
// Direct access is not encouraged. But function implementation // Direct access is not encouraged. But function implementation
// is not available. The return quantity might be anything. // is not available. The return quantity might be anything.
// Find out further about its possible values and correct way of // Find out further about its possible values and correct way of
// access. // access.
int bytes = device->ftdi_ctx->readbuffer_remaining; int bytes = device->ftdi_ctx->readbuffer_remaining;
return bytes; return bytes;
} }
int serial_get_transmitted (serial_t *device)
int
serial_get_transmitted (serial_t *device)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return -1; // EINVAL (Invalid argument)
// This is not possible using libftdi. Look further into it. // This is not possible using libftdi. Look further into it.
return -1; return -1;
} }
int serial_get_line (serial_t *device, int line)
int
serial_get_line (serial_t *device, int line)
{ {
if (device == NULL) if (device == NULL)
return -1; // EINVAL (Invalid argument) return -1; // EINVAL (Invalid argument)
unsigned short int status[2] = {0}; unsigned short int status[2] = {0};
if(ftdi_poll_modem_status(device->ftdi_ctx, status)) { if(ftdi_poll_modem_status(device->ftdi_ctx, status)) {
ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx)); ERROR (device->context, ftdi_get_error_string(device->ftdi_ctx));
return -1; return -1;
} }
switch (line) { switch (line) {
case SERIAL_LINE_DCD: case SERIAL_LINE_DCD:
return (status[0] & MODEM_DCD) == MODEM_DCD; return (status[0] & MODEM_DCD) == MODEM_DCD;
case SERIAL_LINE_CTS: case SERIAL_LINE_CTS:
return (status[0] & MODEM_CTS) == MODEM_CTS; return (status[0] & MODEM_CTS) == MODEM_CTS;
case SERIAL_LINE_DSR: case SERIAL_LINE_DSR:
return (status[0] & MODEM_DSR) == MODEM_DSR; return (status[0] & MODEM_DSR) == MODEM_DSR;
case SERIAL_LINE_RNG: case SERIAL_LINE_RNG:
return (status[0] & MODEM_RNG) == MODEM_RNG; return (status[0] & MODEM_RNG) == MODEM_RNG;
default: default:
return -1; return -1;
} }
return 0; return 0;
} }
int serial_sleep (serial_t *device, unsigned long timeout)
int
serial_sleep (serial_t *device, unsigned long timeout)
{ {
if (device == NULL) if (device == NULL)
return -1; return -1;
INFO (device->context, "Sleep: value=%lu", timeout); INFO (device->context, "Sleep: value=%lu", timeout);
struct timespec ts; struct timespec ts;
ts.tv_sec = (timeout / 1000); ts.tv_sec = (timeout / 1000);
ts.tv_nsec = (timeout % 1000) * 1000000; ts.tv_nsec = (timeout % 1000) * 1000000;
while (nanosleep (&ts, &ts) != 0) { while (nanosleep (&ts, &ts) != 0) {
if (errno != EINTR ) { if (errno != EINTR ) {
SYSERROR (device->context, errno); SYSERROR (device->context, errno);
return -1; return -1;
} }
} }
return 0; return 0;