Discussion:
[PATCH] Fixed purge & added purge_test.c; Fixed C++ bit-or's & const.
Eric Schott
2017-04-10 13:54:15 UTC
Permalink
The FTDI1 purge functionality with FT4232H was not implementing
behavior equivalent to Linux tcflush(3). Added examples/purge_test
which (when using a loopback connector) tests purge/tcflush for both
Linux and FTDI1 UARTs. Testing showed the ftdi.h definitions for
SIO_RESET_PURGE_TX and SIO_RESET_PURGE_RX were "swapped" (i.e., the
former flushed the hardware's RX queue and the latter flushed the
hardware TX queue). After correcting the definitions, the purge
function for the FT4232H works similarly to the behavoir to the Linux
driver for this chip. While the Linux driver correctly purges the
FT232, neither the pre- or post-fix of the FTDI1 library flushed
correctly for the FT232.

For FTDI1 C++ implementation, corrected a const and changed the purge
(and ModemCtl) definitions to not use an enumeration value of zero for
a bit masks. For the later, the enumerations were defined so programs
compiled with the old ftdi.hpp include would work as previously (doing
nothing when the enumeration with the zero value was bit-or'ed into
the argument).

The provided patch is at the user's risk.
No licensing of this patch can preclude its use by the governement of
the United States or The Applied Research Laboratory of The
Pennsylvania State University.
---
examples/CMakeLists.txt | 2 +
examples/purge_test.c | 602
+++++++++++++++++++++
examples/purge_test_results/README.txt | 14 +
.../purge_test_results/purge-16550A-115200.lis | 26 +
examples/purge_test_results/purge-16550A-1200.lis | 26 +
.../purge_test_results/purge-ft232-kernel-1200.lis | 33 ++
.../purge-ft232-libftdi1-post-fix-1200.lis | 33 ++
.../purge-ft232-libftdi1-pre-fix-1200.lis | 34 ++
.../purge-ft4232-kernel-115200.lis | 31 ++
.../purge-ft4232-kernel-1200.lis | 31 ++
.../purge-ft4232-libftdi1-post-fix-115200.lis | 30 +
.../purge-ft4232-libftdi1-post-fix-1200.lis | 30 +
.../purge-ft4232-libftdi1-pre-fix-115200.lis | 32 ++
.../purge-ft4232-libftdi1-pre-fix-1200.lis | 32 ++
ftdipp/ftdi.cpp | 26 +-
ftdipp/ftdi.hpp | 12 +-
src/ftdi.h | 4 +-
17 files changed, 984 insertions(+), 14 deletions(-)
create mode 100644 examples/purge_test.c
create mode 100644 examples/purge_test_results/README.txt
create mode 100644 examples/purge_test_results/purge-16550A-115200.lis
create mode 100644 examples/purge_test_results/purge-16550A-1200.lis
create mode 100644 examples/purge_test_results/purge-ft232-kernel-1200.lis
create mode 100644
examples/purge_test_results/purge-ft232-libftdi1-post-fix-1200.lis
create mode 100644
examples/purge_test_results/purge-ft232-libftdi1-pre-fix-1200.lis
create mode 100644
examples/purge_test_results/purge-ft4232-kernel-115200.lis
create mode 100644
examples/purge_test_results/purge-ft4232-kernel-1200.lis
create mode 100644
examples/purge_test_results/purge-ft4232-libftdi1-post-fix-115200.lis
create mode 100644
examples/purge_test_results/purge-ft4232-libftdi1-post-fix-1200.lis
create mode 100644
examples/purge_test_results/purge-ft4232-libftdi1-pre-fix-115200.lis
create mode 100644
examples/purge_test_results/purge-ft4232-libftdi1-pre-fix-1200.lis

diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 1263c62..bf21557 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -18,6 +18,7 @@ if (EXAMPLES)
add_executable(serial_test serial_test.c)
add_executable(baud_test baud_test.c)
add_executable(stream_test stream_test.c)
+ add_executable(purge_test purge_test.c)
add_executable(eeprom eeprom.c)

# Linkage
@@ -30,6 +31,7 @@ if (EXAMPLES)
target_link_libraries(serial_test ftdi1)
target_link_libraries(baud_test ftdi1)
target_link_libraries(stream_test ftdi1)
+ target_link_libraries(purge_test ftdi1)
target_link_libraries(eeprom ftdi1)

# libftdi++ examples
diff --git a/examples/purge_test.c b/examples/purge_test.c
new file mode 100644
index 0000000..d2c9001
--- /dev/null
+++ b/examples/purge_test.c
@@ -0,0 +1,602 @@
+/* purge_test.c
+ *
+ * Test for purge TX/RX functions.
+ *
+ * The chip must be wired to loop TX data to RX data (loopback).
+ *
+ * This program works with "standard" linux drivers and the FTDI1 library.
+ *
+ * Usage: purge_test [-b baud] [-i interface] [-n msg-size] [-N note]
device-specifier
+ * See usage below for more information on command usage.
+ *
+ * This program works well with the FT4231H which is newer and has large
+ * FIFOs. This program does not work well with FT232, either pre or post
+ * switching the SIO_RESET_PURGE_TX/SIO_RESET_PURGE_RX values.
+ *
+ * This needs testing with other devices, which I do not have.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <signal.h>
+#include <errno.h>
+#include <ftdi.h>
+#include <termios.h> // For baudcodes & linux UARTs
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
+static struct ftdi_context *ftdi = NULL;
+static int dev_fd = -1;
+static char * dev_string = NULL;
+static int baud = 9600;
+static int baud_code = -1;
+static enum ftdi_interface interface = INTERFACE_A;
+static int msg_size = 80;
+
+
+static volatile long long usec_test_start;
+
+
+
+static int ascii2int(const char * str, const char * pgm_name);
+static int baud_2_baud_code(int baud);
+static long int char_cnt_2_usec(int char_count);
+static long int drain();
+static int flush(int queue_selector);
+static long long int get_time_usec();
+
+static const int flushQueueSelector[] = {
+ TCIFLUSH, TCOFLUSH, TCIOFLUSH }; /* See /usr/include/bits/termios.h */
+static const char * flushTestName[] = {
+ "Input-only", "Output-only", "Input+Output" };
+static const char * expected[] = {
+ "last half of message",
+ "first half of message",
+ "a handful of mid-message characters",
+};
+
+
+static const char * chip_types[] = {
+ "am",
+ "bm",
+ "2232C",
+ "R",
+ "2232H",
+ "4232H",
+ "232H",
+ "230X",
+};
+
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#endif
+
+
+
+/**********************************************************************
+ */
+static void
+usage(const char *argv0)
+{
+ fprintf(stderr,
+ "Usage: %s [options...] device-specifier\n"
+ "Flush test for UARTS.\n"
+ " with loopback connector\n"
+ " [-b baud] baud rate (e.g., 300, 600, 1200,
...230400)\n"
+ " [-i {a|b|c|d}] FTDI interface for chips which have
multiple UARTS\n"
+ " [-n msg-size] Number of bytes in test message\n"
+ " [-N note] Note for the output\n"
+ "\n"
+ " device-specifier String specifying the UART. If the
first character\n"
+ " is the '/' character, the program assumes
a Linux UART\n"
+ " is to be tested and the string would be
something like\n"
+ " '/dev/ttyS0' or '/dev/ttyUSB0'. Otherwise,
the program\n"
+ " assumes an FTDI device is being tested
with the FTDI1\n"
+ " library. The device-specifier must be a
string\n"
+ " accepted by the ftdi_usb_open_string
function. An\n"
+ " example would be 'i:0x0403:0x6011[:index]'.\n"
+ "\n"
+ "NOTE: To function correctly, this program requires a loopback
connector\n"
+ " attached to the UART under test.\n"
+ "\n"
+ "Adapted from stream_test.c 2017. Eric Schott <***@psu.edu>\n"
+ "Copyright (C) 2009 Micah Dowty <***@navi.cx>\n"
+ "Adapted for use with libftdi (C) 2010 Uwe Bonnes
<***@elektron.ikp.physik.tu-darmstadt.de>\n",
+ argv0);
+ exit(1);
+}
+
+
+/**********************************************************************
+ */
+int main(int argc, char **argv)
+{
+ int c, i;
+ int option_index;
+ int test;
+ unsigned char * msg;
+ unsigned char * retMsg;
+ char * note = NULL;
+ size_t retMsgSize;
+ long int msg_xmit_time_us;
+ static struct option long_options[] = {{NULL},};
+
+ while ((c = getopt_long(argc, argv, "n:b:i:N:", long_options,
&option_index)) !=- 1)
+ switch (c)
+ {
+ case -1:
+ break;
+ case 'b':
+ baud = ascii2int(optarg, argv[0]);
+ break;
+ case 'i':
+ if (optarg == NULL || strlen(optarg) != 1)
+ usage(argv[0]);
+ switch (optarg[0])
+ {
+ case 'a':
+ case 'A':
+ interface = INTERFACE_A;
+ break;
+
+ case 'b':
+ case 'B':
+ interface = INTERFACE_B;
+ break;
+
+ case 'c':
+ case 'C':
+ interface = INTERFACE_C;
+ break;
+
+ case 'd':
+ case 'D':
+ interface = INTERFACE_D;
+ break;
+
+ default:
+ usage(argv[0]);
+ }
+ break;
+ case 'n':
+ msg_size = ascii2int(optarg, argv[0]);
+ if (msg_size < 1)
+ {
+ fprintf(stderr, "msg-size [-n] must be an integer
greater than 0\n");
+ usage(argv[0]);
+ }
+ break;
+ case 'N':
+ note = optarg;
+ break;
+ default:
+ usage(argv[0]);
+ }
+
+ if (optind == argc)
+ usage(argv[0]);
+
+ if (optind == argc - 1)
+ {
+ // Exactly one extra argument- a dump file
+ dev_string = argv[optind];
+ }
+ else if (optind < argc)
+ {
+ // Too many extra args
+ usage(argv[0]);
+ }
+
+ baud_code = baud_2_baud_code(baud);
+ if (baud_code < 1)
+ {
+ fprintf(stderr, "Invalid baud [-b]\n");
+ usage(argv[0]);
+ }
+
+ if (dev_string[0] == '/')
+ {
+ struct termios termios;
+ dev_fd = open(dev_string, O_NOCTTY | O_RDWR);
+ if (dev_fd < 0)
+ {
+ fprintf(stderr, "Error opening Linux device \"%s\": %s\n",
+ dev_string, strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ if (! isatty(dev_fd))
+ {
+ fprintf(stderr, "Not a TTY device: \"%s\"\n", dev_string);
+ return EXIT_FAILURE;
+ }
+
+ if (tcgetattr(dev_fd, &termios) == -1)
+ {
+ fprintf(stderr, "Error getting TTY attributes for \"%s\":
%s\n",
+ dev_string, strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ cfmakeraw(&termios);
+
+ termios.c_cflag &=
+ ~(CSTOPB | CRTSCTS);
+
+ termios.c_cflag &= ~CSIZE;
+ termios.c_cflag |= CS8;
+
+ cfsetspeed(&termios, baud_code);
+
+ termios.c_cflag |=
+ CLOCAL;
+
+ termios.c_cc[VMIN] = 1; // Character at a time input
+ termios.c_cc[VTIME] = 0; // with blocking
+
+ if (tcsetattr(dev_fd, TCSAFLUSH, &termios) == -1) {
+ fprintf(stderr, "Error setting TTY attributes for \"%s\":
%s\n",
+ dev_string, strerror(errno));
+ return EXIT_FAILURE;
+ }
+ }
+ else
+ {
+
+ if ((ftdi = ftdi_new()) == 0)
+ {
+ fprintf(stderr, "ftdi_new failed\n");
+ return EXIT_FAILURE;
+ }
+
+ if (ftdi_set_interface(ftdi, interface) < 0)
+ {
+ fprintf(stderr, "ftdi_set_interface failed\n");
+ ftdi_free(ftdi);
+ return EXIT_FAILURE;
+ }
+
+ if (ftdi_usb_open_string(ftdi, dev_string) < 0)
+ {
+ fprintf(stderr,"Error opening ftdi device \"%s\": %s\n",
dev_string,
+ ftdi_get_error_string(ftdi));
+ ftdi_free(ftdi);
+ return EXIT_FAILURE;
+ }
+
+ if (ftdi_set_line_property2(ftdi, BITS_8, STOP_BIT_1, NONE,
BREAK_OFF) < 0)
+ {
+ fprintf(stderr,"Error setting line properties ftdi device
\"%s\": %s\n", dev_string,
+ ftdi_get_error_string(ftdi));
+ ftdi_free(ftdi);
+ return EXIT_FAILURE;
+ }
+
+ if (ftdi_set_baudrate(ftdi, baud) < 0)
+ {
+ fprintf(stderr,"Error setting baud rate for ftdi device
\"%s\": %s\n", dev_string,
+ ftdi_get_error_string(ftdi));
+ ftdi_free(ftdi);
+ return EXIT_FAILURE;
+ }
+
+ if (ftdi_setflowctrl(ftdi, SIO_DISABLE_FLOW_CTRL))
+ {
+ fprintf(stderr,"Error setting flow control for ftdi device
\"%s\": %s\n", dev_string,
+ ftdi_get_error_string(ftdi));
+ ftdi_free(ftdi);
+ return EXIT_FAILURE;
+ }
+
+ }
+
+ printf("Purge (tcflush) test for device %s\n", dev_string);
+ if (note)
+ {
+ printf("Note: %s\n", note);
+ }
+ if (dev_fd < 0)
+ {
+ if (ftdi->type >0 && ftdi->type < ARRAY_SIZE(chip_types))
+ printf("FTDI chip type is %d (%s)\n",
+ ftdi->type, chip_types[ftdi->type]);
+ else
+ printf("FTDI chip type is %d (unknown)\n", ftdi->type);
+ }
+
+ printf("# purge_test" );
+ for (c = 1; c < argc; ++c)
+ {
+ const char *p = argv[c];
+ while (*p != '\0')
+ {
+ if (*p == ' ')
+ break;
+ ++p;
+ }
+ if (*p == ' ')
+ printf(" '%s'", argv[c]);
+ else
+ printf(" %s", argv[c]);
+ }
+ printf("\n");
+
+ msg_xmit_time_us = char_cnt_2_usec(msg_size);
+ printf("%d chars at %d baud takes about %.0f ms to transmit\n",
msg_size,
+ baud, msg_xmit_time_us * .001);
+
+ msg = malloc(msg_size + 1);
+ if (msg == NULL)
+ {
+ fprintf(stderr, "Could not allocate send message buffer\n");
+ return EXIT_FAILURE;
+ }
+
+ {
+ char dataChar = '0' + ((get_time_usec() / 1000) % 31);
+ char next = 'A';
+ for (i = 0; i < msg_size; ++i) {
+ if (dataChar == '`')
+ {
+ msg[i] = next++;
+ ++dataChar;
+ }
+ else
+ msg[i] = dataChar++;
+
+ if (dataChar > 'z') {
+ dataChar = '`';
+ }
+ }
+ msg[msg_size] = '\0';
+ }
+
+ printf("TX Message is \"%s\"\n", msg);
+
+ retMsgSize = 2 * msg_size;
+ retMsg = malloc(retMsgSize);
+ if (retMsg == NULL)
+ {
+ fprintf(stderr, "Could not allocate received message buffer\n");
+ return EXIT_FAILURE;
+ }
+
+ flush(TCIOFLUSH);
+
+ for (test = 0; test <= 2; ++test)
+ {
+ long long usec_delay;
+ long long usec_to_now;
+ int rc;
+
+ printf("\n******** Test purge %s; expect %s ********\n"
+ " -- Flushing UART\n",
+ flushTestName[test], expected[test]);
+ flush(TCIOFLUSH);
+ usleep(msg_xmit_time_us);
+ flush(TCIOFLUSH);
+ usleep(100000);
+
+ usec_test_start = get_time_usec();
+ if (dev_fd >= 0)
+ rc = write(dev_fd, msg, msg_size);
+ else
+ rc = ftdi_write_data(ftdi, msg, msg_size);
+
+ if (rc != msg_size)
+ {
+ fprintf(stderr, "Data write was short: %d: %s\n",
+ rc, ftdi_get_error_string(ftdi));
+ exit(1);
+ }
+ usec_to_now = get_time_usec() - usec_test_start;
+ usec_delay = msg_xmit_time_us / 2 - usec_to_now;
+ if (usec_delay < 0)
+ usec_delay = 0;
+ printf(" -- %9.1f ms Write completes; delaying to TX midpoint
(%.1f ms)\n",
+ usec_to_now * .001, usec_delay * .001);
+ if (usec_delay > 0)
+ usleep(usec_delay);
+
+ printf(" -- %9.1f ms Issuing %s flush (purge)\n",
+ (get_time_usec() - usec_test_start) * .001,
+ flushTestName[test]);
+ flush(flushQueueSelector[test]);
+
+ printf(" -- %9.1f ms Calling drain to wait for transmit to
complete\n",
+ (get_time_usec() - usec_test_start) * .001);
+ drain();
+
+ usec_to_now = get_time_usec() - usec_test_start;
+
+ /* If input only flush, check drain time. */
+ if (flushQueueSelector[test] == TCIFLUSH &&
+ usec_to_now < (msg_xmit_time_us * 90ll) / 100ll)
+ {
+ usec_delay = (msg_xmit_time_us * 110ll) / 100ll - usec_to_now;
+ printf(" -- %9.1f ms Drain() completed too early; expected
at least %.1f ms\n"
+ " Delaying for %.1f ms\n",
+ usec_to_now * .001,
+ ((msg_xmit_time_us * 90ll) / 100ll) * .001,
+ usec_delay * .001);
+ usleep(usec_delay);
+ }
+ else
+ {
+ printf(" -- %9.1f ms Drain() reports completed; timing OK;
delaying for 4 bytes\n",
+ (get_time_usec() - usec_test_start) * .001);
+ usleep(char_cnt_2_usec(4));
+ }
+
+ printf(" -- %9.1f ms Reading data.\n",
+ (get_time_usec() - usec_test_start) * .001);
+ if (dev_fd >= 0)
+ rc = read(dev_fd, retMsg, retMsgSize);
+ else
+ rc = ftdi_read_data(ftdi, retMsg, retMsgSize - 1);
+
+ usec_to_now = get_time_usec() - usec_test_start;
+ if (rc < 0)
+ {
+ fprintf(stderr, " -- %9.1f ms Read returned error %s\n",
+ usec_to_now * .001,
+ (dev_fd >= 0 ? strerror(errno) :
ftdi_get_error_string(ftdi)));
+ exit(1);
+ }
+ retMsg[rc] = '\0';
+ printf(" -- %9.1f ms Read returns %d bytes; msg: \"%s\"\n",
+ usec_to_now * .001, rc, retMsg);
+
+ usleep(char_cnt_2_usec(10));
+
+ }
+
+
+ if (dev_fd >= 0)
+ {
+ close(dev_fd);
+ }
+ else
+ {
+ ftdi_usb_close(ftdi);
+ ftdi_free(ftdi);
+ }
+
+ exit (0);
+}
+
+/**********************************************************************
+ */
+static int ascii2int(const char * str, const char * pgm_name)
+{
+ int rc;
+ char * endptr;
+ if (str == NULL || strlen(str) == 0)
+ usage(pgm_name);
+ rc = strtol(str, &endptr, 10);
+ if (endptr == str || *endptr != '\0')
+ usage(pgm_name);
+ return rc;
+}
+
+
+/**********************************************************************
+ */
+static struct Baud_Table {
+ int32_t baud, baud_code;
+} baud_table [] =
+{
+ { 50, B50 },
+ { 75, B75 },
+ { 110, B110 },
+ { 134, B134 },
+ { 150, B150 },
+ { 200, B200 },
+ { 300, B300 },
+ { 600, B600 },
+ { 1200, B1200 },
+ { 1800, B1800 },
+ { 2400, B2400 },
+ { 4800, B4800 },
+ { 9600, B9600 },
+ { 19200, B19200 },
+ { 38400, B38400 },
+ { 57600, B57600 },
+ { 115200, B115200 },
+ { 230400, B230400 },
+ { -1, -1, }
+};
+
+/**********************************************************************
+ */
+static int baud_2_baud_code(int baud)
+{
+ struct Baud_Table *p;
+
+ for (p = baud_table ; p->baud != -1; ++p) {
+ if (p->baud == baud)
+ break;
+ }
+ return p->baud_code;
+}
+
+
+static long int char_cnt_2_usec(int char_count)
+{
+ long long bits = 8 + 1 + 1; /* Number of bits in
each character */
+ bits *= (char_count == 0 ? 1 : char_count); /* Total number of bits */
+ bits *= 1000000; /* Convert to us */
+ lldiv_t parts = lldiv(bits, baud); /* Number of us for
message */
+ return (parts.quot + 1);
+}
+
+
+static long int drain()
+{
+ long int rc = 0;
+ long long start_time = get_time_usec();
+ if (dev_fd >= 0)
+ rc = tcdrain(dev_fd);
+ else
+ {
+ long int sleep_interval = char_cnt_2_usec(10);
+ while (1) {
+ unsigned short modem_status = 0;
+ int rc = ftdi_poll_modem_status(ftdi, &modem_status);
+ if (rc < 0)
+ return -1;
+ if (modem_status & (1 << (6 + 8))) {
+ break;
+ }
+ usleep(sleep_interval);
+ }
+ }
+ if (rc < 0)
+ return rc;
+ usleep(char_cnt_2_usec(2));
+ return get_time_usec() - start_time;
+}
+
+
+static int flush(int queue_selector)
+{
+ int rc;
+ if (dev_fd >= 0)
+ rc = tcflush(dev_fd, queue_selector);
+ else
+ {
+ switch (queue_selector) {
+
+ case TCIOFLUSH:
+ rc = ftdi_usb_purge_buffers(ftdi);
+ break;
+
+ case TCIFLUSH:
+ rc = ftdi_usb_purge_rx_buffer(ftdi);
+ break;
+
+ case TCOFLUSH:
+ rc = ftdi_usb_purge_tx_buffer(ftdi);
+ break;
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ return rc;
+}
+
+
+static long long int get_time_usec()
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000ll + tv.tv_usec;
+}
diff --git a/examples/purge_test_results/README.txt
b/examples/purge_test_results/README.txt
new file mode 100644
index 0000000..8daa99e
--- /dev/null
+++ b/examples/purge_test_results/README.txt
@@ -0,0 +1,14 @@
+This directory contains test output for tests of the purge (tcflush())
+operations. The 16550 files display the Linux driver default behavior.
+The remaining files display behavior for other tests cases.
+
+The tests run three tests which consist of
+ - Queuing a block of data for TX output
+ - Waiting for 1/2 the transmit time
+ - Issuing one of the three purge (flush) operations
+ - Waiting for the TX hardware queue to empty (drain)
+
+The FTDI1 library purge function for the FT4232H works similarly to
+the behavoir to the Linux driver for this chip. While the Linux
+driver correctly purges the FT232, neither the pre- or post-fix of the
+FTDI1 library flushed correctly for the FT232.
diff --git a/examples/purge_test_results/purge-16550A-115200.lis
b/examples/purge_test_results/purge-16550A-115200.lis
new file mode 100644
index 0000000..3067786
--- /dev/null
+++ b/examples/purge_test_results/purge-16550A-115200.lis
@@ -0,0 +1,26 @@
+Purge (tcflush) test for device /dev/ttyS0
+Note: Standard 16550A UART
+# purge_test -b 115200 -n 100 '-NStandard 16550A UART' /dev/ttyS0
+100 chars at 115200 baud takes about 9 ms to transmit
+TX Message is
"KLMNOPQRSTUVWXYZ[\]^_AabcdefghijklmnopqrstuvwxyzBabcdefghijklmnopqrstuvwxyzCabcdefghijklmnopqrstuvwx"
+
+******** Test purge Input-only; expect last half of message ********
+ -- 0.0 ms Write completes; delaying to TX midpoint (4.3 ms)
+ -- 4.4 ms Issuing Input-only flush (purge)
+ -- 4.4 ms Calling drain to wait for transmit to complete
+ -- 10.5 ms Output (drain( should be completed; delaying for 4 bytes
+ -- 10.5 ms Read returns 53 bytes; msg:
"zBabcdefghijklmnopqrstuvwxyzCabcdefghijklmnopqrstuvwx"
+
+******** Test purge Output-only; expect first half of message ********
+ -- 0.0 ms Write completes; delaying to TX midpoint (4.3 ms)
+ -- 4.7 ms Issuing Output-only flush (purge)
+ -- 4.7 ms Calling drain to wait for transmit to complete
+ -- 6.9 ms Output (drain( should be completed; delaying for 4 bytes
+ -- 6.9 ms Read returns 64 bytes; msg:
"KLMNOPQRSTUVWXYZ[\]^_AabcdefghijklmnopqrstuvwxyzBabcdefghijklmno"
+
+******** Test purge Input+Output; expect a handful of mid-message
characters ********
+ -- 0.0 ms Write completes; delaying to TX midpoint (4.3 ms)
+ -- 4.4 ms Issuing Input+Output flush (purge)
+ -- 4.4 ms Calling drain to wait for transmit to complete
+ -- 6.0 ms Output (drain( should be completed; delaying for 4 bytes
+ -- 6.0 ms Read returns 16 bytes; msg: "zBabcdefghijklmn"
diff --git a/examples/purge_test_results/purge-16550A-1200.lis
b/examples/purge_test_results/purge-16550A-1200.lis
new file mode 100644
index 0000000..79e942f
--- /dev/null
+++ b/examples/purge_test_results/purge-16550A-1200.lis
@@ -0,0 +1,26 @@
+Purge (tcflush) test for device /dev/ttyS0
+Note: Standard 16550A UART
+# purge_test -b 1200 -n 100 '-NStandard 16550A UART' /dev/ttyS0
+100 chars at 1200 baud takes about 833 ms to transmit
+TX Message is
"?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_AabcdefghijklmnopqrstuvwxyzBabcdefghijklmnopqrstuvwxyzCabcdefghijkl"
+
+******** Test purge Input-only; expect last half of message ********
+ -- 0.0 ms Write completes; delaying to TX midpoint (416.6 ms)
+ -- 416.8 ms Issuing Input-only flush (purge)
+ -- 416.8 ms Calling drain to wait for transmit to complete
+ -- 849.9 ms Output (drain( should be completed; delaying for 4 bytes
+ -- 849.9 ms Read returns 50 bytes; msg:
"qrstuvwxyzBabcdefghijklmnopqrstuvwxyzCabcdefghijkl"
+
+******** Test purge Output-only; expect first half of message ********
+ -- 0.0 ms Write completes; delaying to TX midpoint (416.6 ms)
+ -- 416.7 ms Issuing Output-only flush (purge)
+ -- 416.8 ms Calling drain to wait for transmit to complete
+ -- 550.6 ms Output (drain( should be completed; delaying for 4 bytes
+ -- 550.6 ms Read returns 64 bytes; msg:
"?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_AabcdefghijklmnopqrstuvwxyzBabc"
+
+******** Test purge Input+Output; expect a handful of mid-message
characters ********
+ -- 0.0 ms Write completes; delaying to TX midpoint (416.6 ms)
+ -- 416.7 ms Issuing Input+Output flush (purge)
+ -- 416.8 ms Calling drain to wait for transmit to complete
+ -- 551.4 ms Output (drain( should be completed; delaying for 4 bytes
+ -- 551.5 ms Read returns 14 bytes; msg: "qrstuvwxyzBabc"
diff --git a/examples/purge_test_results/purge-ft232-kernel-1200.lis
b/examples/purge_test_results/purge-ft232-kernel-1200.lis
new file mode 100644
index 0000000..5d516fd
--- /dev/null
+++ b/examples/purge_test_results/purge-ft232-kernel-1200.lis
@@ -0,0 +1,33 @@
+Purge (tcflush) test for device /dev/ttyUSB0
+Note: FT232 with Linux drivers
+# purge_test -b 1200 '-NFT232 with Linux drivers' -n 60 /dev/ttyUSB0
+60 chars at 1200 baud takes about 500 ms to transmit
+TX Message is
"JKLMNOPQRSTUVWXYZ[\]^_AabcdefghijklmnopqrstuvwxyzBabcdefghij"
+
+******** Test purge Input-only; expect last half of message ********
+ -- Flushing UART
+ -- 0.0 ms Write completes; delaying to TX midpoint (250.0 ms)
+ -- 250.1 ms Issuing Input-only flush (purge)
+ -- 250.1 ms Calling drain to wait for transmit to complete
+ -- 275.2 ms Drain() completed too early; expected at least 450.0 ms
+ Delaying for 274.8 ms
+ -- 550.1 ms Reading data.
+ -- 550.1 ms Read returns 32 bytes; msg:
"fghijklmnopqrstuvwxyzBabcdefghij"
+
+******** Test purge Output-only; expect first half of message ********
+ -- Flushing UART
+ -- 0.0 ms Write completes; delaying to TX midpoint (250.0 ms)
+ -- 250.1 ms Issuing Output-only flush (purge)
+ -- 250.1 ms Calling drain to wait for transmit to complete
+ -- 274.2 ms Drain() reports completed; timing OK; delaying for 4
bytes
+ -- 307.7 ms Reading data.
+ -- 307.7 ms Read returns 35 bytes; msg:
"JKLMNOPQRSTUVWXYZ[\]^_Aabcdefghijkl"
+
+******** Test purge Input+Output; expect a handful of mid-message
characters ********
+ -- Flushing UART
+ -- 0.0 ms Write completes; delaying to TX midpoint (250.0 ms)
+ -- 250.1 ms Issuing Input+Output flush (purge)
+ -- 250.2 ms Calling drain to wait for transmit to complete
+ -- 274.8 ms Drain() reports completed; timing OK; delaying for 4
bytes
+ -- 308.3 ms Reading data.
+ -- 308.3 ms Read returns 8 bytes; msg: "efghijkl"
diff --git
a/examples/purge_test_results/purge-ft232-libftdi1-post-fix-1200.lis
b/examples/purge_test_results/purge-ft232-libftdi1-post-fix-1200.lis
new file mode 100644
index 0000000..a5106b2
--- /dev/null
+++ b/examples/purge_test_results/purge-ft232-libftdi1-post-fix-1200.lis
@@ -0,0 +1,33 @@
+Purge (tcflush) test for device i:0x403:0x6001:1
+Note: FT232 with FTDI1 drivers post-fix
+FTDI chip type is 0 (unknown)
+# purge_test -b 1200 '-NFT232 with FTDI1 drivers post-fix' -n 60
i:0x403:0x6001:1
+60 chars at 1200 baud takes about 500 ms to transmit
+TX Message is
"3456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_Aabcdefghijklmn"
+
+******** Test purge Input-only; expect last half of message ********
+ -- Flushing UART
+ -- 0.3 ms Write completes; delaying to TX midpoint (249.7 ms)
+ -- 250.1 ms Issuing Input-only flush (purge)
+ -- 250.3 ms Calling drain to wait for transmit to complete
+ -- 518.1 ms Drain() reports completed; timing OK; delaying for 4
bytes
+ -- 551.6 ms Reading data.
+ -- 568.3 ms Read returns 60 bytes; msg:
"3456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_Aabcdefghijklmn"
+
+******** Test purge Output-only; expect first half of message ********
+ -- Flushing UART
+ -- 0.2 ms Write completes; delaying to TX midpoint (249.8 ms)
+ -- 250.1 ms Issuing Output-only flush (purge)
+ -- 250.3 ms Calling drain to wait for transmit to complete
+ -- 267.1 ms Drain() reports completed; timing OK; delaying for 4
bytes
+ -- 300.6 ms Reading data.
+ -- 300.9 ms Read returns 0 bytes; msg: ""
+
+******** Test purge Input+Output; expect a handful of mid-message
characters ********
+ -- Flushing UART
+ -- 0.2 ms Write completes; delaying to TX midpoint (249.8 ms)
+ -- 250.1 ms Issuing Input+Output flush (purge)
+ -- 250.7 ms Calling drain to wait for transmit to complete
+ -- 267.6 ms Drain() reports completed; timing OK; delaying for 4
bytes
+ -- 301.1 ms Reading data.
+ -- 301.4 ms Read returns 29 bytes; msg:
"RSTUVWXYZ[\]^_Aabcdefghijklmn"
diff --git
a/examples/purge_test_results/purge-ft232-libftdi1-pre-fix-1200.lis
b/examples/purge_test_results/purge-ft232-libftdi1-pre-fix-1200.lis
new file mode 100644
index 0000000..921bdb6
--- /dev/null
+++ b/examples/purge_test_results/purge-ft232-libftdi1-pre-fix-1200.lis
@@ -0,0 +1,34 @@
+Purge (tcflush) test for device i:0x403:0x6001:1
+Note: FT232 with FTDI1 drivers pre-fix
+FTDI chip type is 0 (unknown)
+# purge_test -b 1200 '-NFT232 with FTDI1 drivers pre-fix' -n 60
i:0x403:0x6001:1
+60 chars at 1200 baud takes about 500 ms to transmit
+TX Message is
"3456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_Aabcdefghijklmn"
+
+******** Test purge Input-only; expect last half of message ********
+ -- Flushing UART
+ -- 0.3 ms Write completes; delaying to TX midpoint (249.7 ms)
+ -- 250.1 ms Issuing Input-only flush (purge)
+ -- 250.3 ms Calling drain to wait for transmit to complete
+ -- 267.3 ms Drain() completed too early; expected at least 450.0 ms
+ Delaying for 282.7 ms
+ -- 550.1 ms Reading data.
+ -- 550.3 ms Read returns 0 bytes; msg: ""
+
+******** Test purge Output-only; expect first half of message ********
+ -- Flushing UART
+ -- 0.2 ms Write completes; delaying to TX midpoint (249.8 ms)
+ -- 250.1 ms Issuing Output-only flush (purge)
+ -- 250.3 ms Calling drain to wait for transmit to complete
+ -- 267.3 ms Drain() reports completed; timing OK; delaying for 4
bytes
+ -- 300.7 ms Reading data.
+ -- 301.0 ms Read returns 29 bytes; msg:
"RSTUVWXYZ[\]^_Aabcdefghijklmn"
+
+******** Test purge Input+Output; expect a handful of mid-message
characters ********
+ -- Flushing UART
+ -- 0.2 ms Write completes; delaying to TX midpoint (249.8 ms)
+ -- 250.1 ms Issuing Input+Output flush (purge)
+ -- 250.9 ms Calling drain to wait for transmit to complete
+ -- 268.2 ms Drain() reports completed; timing OK; delaying for 4
bytes
+ -- 301.7 ms Reading data.
+ -- 315.7 ms Read returns 31 bytes; msg:
"3456789:;<=>?@ABCDEFGHIJKLMNOPQ"
diff --git a/examples/purge_test_results/purge-ft4232-kernel-115200.lis
b/examples/purge_test_results/purge-ft4232-kernel-115200.lis
new file mode 100644
index 0000000..204cb78
--- /dev/null
+++ b/examples/purge_test_results/purge-ft4232-kernel-115200.lis
@@ -0,0 +1,31 @@
+Purge (tcflush) test for device /dev/ttyUSB1
+Note: FT4232-linux-driver
+# purge_test -b 115200 -n 100 -NFT4232-linux-driver /dev/ttyUSB1
+100 chars at 115200 baud takes about 9 ms to transmit
+TX Message is
">?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_AabcdefghijklmnopqrstuvwxyzBabcdefghijklmnopqrstuvwxyzCabcdefghijk"
+
+******** Test purge Input-only; expect last half of message ********
+ -- 0.1 ms Write completes; delaying to TX midpoint (4.3 ms)
+ -- 4.6 ms Issuing Input-only flush (purge)
+ -- 4.7 ms Calling drain to wait for transmit to complete
+ -- 5.6 ms Drain() completed too early; expected at least 7.8 ms
+ Delaying for 3.9 ms
+ -- 9.8 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 10.3 ms Reading data.
+ -- 10.3 ms Read returns 60 bytes; msg:
"fghijklmnopqrstuvwxyzBabcdefghijklmnopqrstuvwxyzCabcdefghijk"
+
+******** Test purge Output-only; expect first half of message ********
+ -- 0.0 ms Write completes; delaying to TX midpoint (4.3 ms)
+ -- 4.4 ms Issuing Output-only flush (purge)
+ -- 4.4 ms Calling drain to wait for transmit to complete
+ -- 5.1 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 5.5 ms Reading data.
+ -- 5.5 ms Read returns 58 bytes; msg:
">?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_Aabcdefghijklmnopqrstuvw"
+
+******** Test purge Input+Output; expect a handful of mid-message
characters ********
+ -- 0.0 ms Write completes; delaying to TX midpoint (4.3 ms)
+ -- 4.4 ms Issuing Input+Output flush (purge)
+ -- 4.4 ms Calling drain to wait for transmit to complete
+ -- 5.5 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 5.9 ms Reading data.
+ -- 5.9 ms Read returns 23 bytes; msg: "fghijklmnopqrstuvwxyzBa"
diff --git a/examples/purge_test_results/purge-ft4232-kernel-1200.lis
b/examples/purge_test_results/purge-ft4232-kernel-1200.lis
new file mode 100644
index 0000000..2235df2
--- /dev/null
+++ b/examples/purge_test_results/purge-ft4232-kernel-1200.lis
@@ -0,0 +1,31 @@
+Purge (tcflush) test for device /dev/ttyUSB1
+Note: FT4232-linux-driver
+# purge_test -b 1200 -n 100 -NFT4232-linux-driver /dev/ttyUSB1
+100 chars at 1200 baud takes about 833 ms to transmit
+TX Message is
"23456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_AabcdefghijklmnopqrstuvwxyzBabcdefghijklmnopqrstuvwxyz"
+
+******** Test purge Input-only; expect last half of message ********
+ -- 0.0 ms Write completes; delaying to TX midpoint (416.6 ms)
+ -- 416.7 ms Issuing Input-only flush (purge)
+ -- 416.8 ms Calling drain to wait for transmit to complete
+ -- 441.2 ms Drain() completed too early; expected at least 750.0 ms
+ Delaying for 475.5 ms
+ -- 916.7 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 950.1 ms Reading data.
+ -- 950.2 ms Read returns 51 bytes; msg:
"cdefghijklmnopqrstuvwxyzBabcdefghijklmnopqrstuvwxyz"
+
+******** Test purge Output-only; expect first half of message ********
+ -- 0.0 ms Write completes; delaying to TX midpoint (416.6 ms)
+ -- 416.7 ms Issuing Output-only flush (purge)
+ -- 416.8 ms Calling drain to wait for transmit to complete
+ -- 441.3 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 474.9 ms Reading data.
+ -- 474.9 ms Read returns 56 bytes; msg:
"23456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_Aabcdefghi"
+
+******** Test purge Input+Output; expect a handful of mid-message
characters ********
+ -- 0.0 ms Write completes; delaying to TX midpoint (416.7 ms)
+ -- 416.9 ms Issuing Input+Output flush (purge)
+ -- 417.0 ms Calling drain to wait for transmit to complete
+ -- 442.2 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 475.6 ms Reading data.
+ -- 475.6 ms Read returns 7 bytes; msg: "NOPQRST"
diff --git
a/examples/purge_test_results/purge-ft4232-libftdi1-post-fix-115200.lis
b/examples/purge_test_results/purge-ft4232-libftdi1-post-fix-115200.lis
new file mode 100644
index 0000000..6985763
--- /dev/null
+++ b/examples/purge_test_results/purge-ft4232-libftdi1-post-fix-115200.lis
@@ -0,0 +1,30 @@
+Purge (tcflush) test for device i:0x403:0xdaed
+Note: FT4232-libftdi1-post-fix
+FTDI chip type is 5 (4232H)
+# purge_test -b 115200 -n 100 -NFT4232-libftdi1-post-fix -i B
i:0x403:0xdaed
+100 chars at 115200 baud takes about 9 ms to transmit
+TX Message is
"?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_AabcdefghijklmnopqrstuvwxyzBabcdefghijklmnopqrstuvwxyzCabcdefghijkl"
+
+******** Test purge Input-only; expect last half of message ********
+ -- 0.2 ms Write completes; delaying to TX midpoint (4.2 ms)
+ -- 4.4 ms Issuing Input-only flush (purge)
+ -- 4.5 ms Calling drain to wait for transmit to complete
+ -- 9.0 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 9.4 ms Reading data.
+ -- 9.8 ms Read returns 51 bytes; msg:
"pqrstuvwxyzBabcdefghijklmnopqrstuvwxyzCabcdefghijkl"
+
+******** Test purge Output-only; expect first half of message ********
+ -- 0.2 ms Write completes; delaying to TX midpoint (4.1 ms)
+ -- 4.4 ms Issuing Output-only flush (purge)
+ -- 4.6 ms Calling drain to wait for transmit to complete
+ -- 5.1 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 5.4 ms Reading data.
+ -- 5.7 ms Read returns 52 bytes; msg:
"?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_Aabcdefghijklmnopqr"
+
+******** Test purge Input+Output; expect a handful of mid-message
characters ********
+ -- 0.2 ms Write completes; delaying to TX midpoint (4.2 ms)
+ -- 4.6 ms Issuing Input+Output flush (purge)
+ -- 4.9 ms Calling drain to wait for transmit to complete
+ -- 5.2 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 5.5 ms Reading data.
+ -- 6.7 ms Read returns 3 bytes; msg: "tuv"
diff --git
a/examples/purge_test_results/purge-ft4232-libftdi1-post-fix-1200.lis
b/examples/purge_test_results/purge-ft4232-libftdi1-post-fix-1200.lis
new file mode 100644
index 0000000..406d12d
--- /dev/null
+++ b/examples/purge_test_results/purge-ft4232-libftdi1-post-fix-1200.lis
@@ -0,0 +1,30 @@
+Purge (tcflush) test for device i:0x403:0xdaed
+Note: FT4232-libftdi1-post-fix
+FTDI chip type is 5 (4232H)
+# purge_test -b 1200 -n 100 -NFT4232-libftdi1-post-fix -i B i:0x403:0xdaed
+100 chars at 1200 baud takes about 833 ms to transmit
+TX Message is
"MNOPQRSTUVWXYZ[\]^_AabcdefghijklmnopqrstuvwxyzBabcdefghijklmnopqrstuvwxyzCabcdefghijklmnopqrstuvwxyz"
+
+******** Test purge Input-only; expect last half of message ********
+ -- 0.4 ms Write completes; delaying to TX midpoint (416.3 ms)
+ -- 416.8 ms Issuing Input-only flush (purge)
+ -- 417.1 ms Calling drain to wait for transmit to complete
+ -- 853.7 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 887.2 ms Reading data.
+ -- 887.8 ms Read returns 51 bytes; msg:
"cdefghijklmnopqrstuvwxyzCabcdefghijklmnopqrstuvwxyz"
+
+******** Test purge Output-only; expect first half of message ********
+ -- 0.5 ms Write completes; delaying to TX midpoint (416.2 ms)
+ -- 416.7 ms Issuing Output-only flush (purge)
+ -- 417.0 ms Calling drain to wait for transmit to complete
+ -- 434.0 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 467.4 ms Reading data.
+ -- 467.9 ms Read returns 51 bytes; msg:
"MNOPQRSTUVWXYZ[\]^_AabcdefghijklmnopqrstuvwxyzBabcd"
+
+******** Test purge Input+Output; expect a handful of mid-message
characters ********
+ -- 0.2 ms Write completes; delaying to TX midpoint (416.4 ms)
+ -- 416.7 ms Issuing Input+Output flush (purge)
+ -- 417.0 ms Calling drain to wait for transmit to complete
+ -- 433.8 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 467.5 ms Reading data.
+ -- 468.5 ms Read returns 2 bytes; msg: "cd"
diff --git
a/examples/purge_test_results/purge-ft4232-libftdi1-pre-fix-115200.lis
b/examples/purge_test_results/purge-ft4232-libftdi1-pre-fix-115200.lis
new file mode 100644
index 0000000..395c546
--- /dev/null
+++ b/examples/purge_test_results/purge-ft4232-libftdi1-pre-fix-115200.lis
@@ -0,0 +1,32 @@
+Purge (tcflush) test for device i:0x403:0xdaed
+Note: FT4232-libftdi1-pre-fix
+FTDI chip type is 5 (4232H)
+# purge_test -b 115200 -n 100 -NFT4232-libftdi1-pre-fix -i B i:0x403:0xdaed
+100 chars at 115200 baud takes about 9 ms to transmit
+TX Message is
"JKLMNOPQRSTUVWXYZ[\]^_AabcdefghijklmnopqrstuvwxyzBabcdefghijklmnopqrstuvwxyzCabcdefghijklmnopqrstuvw"
+
+******** Test purge Input-only; expect last half of message ********
+ -- 0.1 ms Write completes; delaying to TX midpoint (4.2 ms)
+ -- 4.4 ms Issuing Input-only flush (purge)
+ -- 4.5 ms Calling drain to wait for transmit to complete
+ -- 4.8 ms Drain() completed too early; expected at least 7.8 ms
+ Delaying for 4.7 ms
+ -- 9.6 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 10.0 ms Reading data.
+ -- 10.2 ms Read returns 52 bytes; msg:
"JKLMNOPQRSTUVWXYZ[\]^_AabcdefghijklmnopqrstuvwxyzBab"
+
+******** Test purge Output-only; expect first half of message ********
+ -- 0.1 ms Write completes; delaying to TX midpoint (4.3 ms)
+ -- 4.4 ms Issuing Output-only flush (purge)
+ -- 4.6 ms Calling drain to wait for transmit to complete
+ -- 8.9 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 9.3 ms Reading data.
+ -- 9.6 ms Read returns 50 bytes; msg:
"abcdefghijklmnopqrstuvwxyzCabcdefghijklmnopqrstuvw"
+
+******** Test purge Input+Output; expect a handful of mid-message
characters ********
+ -- 0.2 ms Write completes; delaying to TX midpoint (4.1 ms)
+ -- 4.4 ms Issuing Input+Output flush (purge)
+ -- 4.7 ms Calling drain to wait for transmit to complete
+ -- 5.0 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 5.4 ms Reading data.
+ -- 5.6 ms Read returns 0 bytes; msg: ""
diff --git
a/examples/purge_test_results/purge-ft4232-libftdi1-pre-fix-1200.lis
b/examples/purge_test_results/purge-ft4232-libftdi1-pre-fix-1200.lis
new file mode 100644
index 0000000..823f8e6
--- /dev/null
+++ b/examples/purge_test_results/purge-ft4232-libftdi1-pre-fix-1200.lis
@@ -0,0 +1,32 @@
+Purge (tcflush) test for device i:0x403:0xdaed
+Note: FT4232-libftdi1-pre-fix
+FTDI chip type is 5 (4232H)
+# purge_test -b 1200 -n 100 -NFT4232-libftdi1-pre-fix -i B i:0x403:0xdaed
+100 chars at 1200 baud takes about 833 ms to transmit
+TX Message is
"KLMNOPQRSTUVWXYZ[\]^_AabcdefghijklmnopqrstuvwxyzBabcdefghijklmnopqrstuvwxyzCabcdefghijklmnopqrstuvwx"
+
+******** Test purge Input-only; expect last half of message ********
+ -- 0.2 ms Write completes; delaying to TX midpoint (416.4 ms)
+ -- 416.7 ms Issuing Input-only flush (purge)
+ -- 416.8 ms Calling drain to wait for transmit to complete
+ -- 433.6 ms Drain() completed too early; expected at least 750.0 ms
+ Delaying for 483.0 ms
+ -- 917.0 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 950.6 ms Reading data.
+ -- 951.6 ms Read returns 51 bytes; msg:
"KLMNOPQRSTUVWXYZ[\]^_AabcdefghijklmnopqrstuvwxyzBab"
+
+******** Test purge Output-only; expect first half of message ********
+ -- 0.3 ms Write completes; delaying to TX midpoint (416.4 ms)
+ -- 416.7 ms Issuing Output-only flush (purge)
+ -- 416.9 ms Calling drain to wait for transmit to complete
+ -- 851.5 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 884.9 ms Reading data.
+ -- 885.4 ms Read returns 51 bytes; msg:
"abcdefghijklmnopqrstuvwxyzCabcdefghijklmnopqrstuvwx"
+
+******** Test purge Input+Output; expect a handful of mid-message
characters ********
+ -- 0.2 ms Write completes; delaying to TX midpoint (416.5 ms)
+ -- 416.7 ms Issuing Input+Output flush (purge)
+ -- 417.1 ms Calling drain to wait for transmit to complete
+ -- 434.1 ms Output (drain) should be completed; delaying for 4 bytes
+ -- 467.5 ms Reading data.
+ -- 467.8 ms Read returns 2 bytes; msg: "ab"
diff --git a/ftdipp/ftdi.cpp b/ftdipp/ftdi.cpp
index 92b6e1f..e6bae47 100644
--- a/ftdipp/ftdi.cpp
+++ b/ftdipp/ftdi.cpp
@@ -144,12 +144,26 @@ int Context::reset()

int Context::flush(int mask)
{
- int ret = 1;
+ int ret;

- if (mask & Input)
- ret &= ftdi_usb_purge_rx_buffer(d->ftdi);
- if (mask & Output)
- ret &= ftdi_usb_purge_tx_buffer(d->ftdi);
+ switch (mask & (Input | Output)) {
+ case Input:
+ ret = ftdi_usb_purge_rx_buffer(d->ftdi);
+ break;
+
+ case Output:
+ ret = ftdi_usb_purge_tx_buffer(d->ftdi);
+ break;
+
+ case Input | Output:
+ ret = ftdi_usb_purge_buffers(d->ftdi);
+ break;
+
+ default:
+ d->ftdi->error_str = "Wrong arguments";
+ ret = -101;
+ break;
+ }

return ret;
}
@@ -219,7 +233,7 @@ int Context::read_chunk_size()
return chunk;
}

-int Context::write(unsigned char *buf, int size)
+int Context::write(const unsigned char *buf, int size)
{
return ftdi_write_data(d->ftdi, buf, size);
}
diff --git a/ftdipp/ftdi.hpp b/ftdipp/ftdi.hpp
index a438d96..ae6adbc 100644
--- a/ftdipp/ftdi.hpp
+++ b/ftdipp/ftdi.hpp
@@ -55,16 +55,16 @@ public:
*/
enum Direction
{
- Input,
- Output
+ Input = 0x2,
+ Output = 0x1,
};

/*! \brief Modem control flags.
*/
enum ModemCtl
{
- Dtr,
- Rts
+ Dtr = 0x2,
+ Rts = 0x1,
};

/* Constructor, Destructor */
@@ -100,7 +100,7 @@ public:

/* I/O */
int read(unsigned char *buf, int size);
- int write(unsigned char *buf, int size);
+ int write(const unsigned char *buf, int size);
int set_read_chunk_size(unsigned int chunksize);
int set_write_chunk_size(unsigned int chunksize);
int read_chunk_size();
@@ -108,7 +108,7 @@ public:

/* Async IO
TODO: should wrap?
- int writeAsync(unsigned char *buf, int size);
+ int writeAsync(const unsigned char *buf, int size);
void asyncComplete(int wait_for_more);
*/

diff --git a/src/ftdi.h b/src/ftdi.h
index bb66c53..acc1869 100644
--- a/src/ftdi.h
+++ b/src/ftdi.h
@@ -173,8 +173,8 @@ enum ftdi_module_detach_mode


#define SIO_RESET_SIO 0
-#define SIO_RESET_PURGE_RX 1
-#define SIO_RESET_PURGE_TX 2
+#define SIO_RESET_PURGE_TX 1
+#define SIO_RESET_PURGE_RX 2

#define SIO_DISABLE_FLOW_CTRL 0x0
#define SIO_RTS_CTS_HS (0x1 << 8)
--
2.1.4



--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+***@developer.intra2net.com
Thomas Jarosch
2017-04-21 16:23:38 UTC
Permalink
Hello Eric,

thanks for your patch! Some questions below.
Post by Eric Schott
The provided patch is at the user's risk.
No licensing of this patch can preclude its use by the governement of
the United States or The Applied Research Laboratory of The
Pennsylvania State University.
would you be ok with licensing the purge_test.c code
as GPL v2 like the other example codes?

That would still fulfill your "license requirement" above.

Perhaps it's a good idea to split the purge fix,
the new example code and the C++ fixes into three (logical) commits.
Post by Eric Schott
diff --git a/src/ftdi.h b/src/ftdi.h
index bb66c53..acc1869 100644
--- a/src/ftdi.h
+++ b/src/ftdi.h
@@ -173,8 +173,8 @@ enum ftdi_module_detach_mode
#define SIO_RESET_SIO 0
-#define SIO_RESET_PURGE_RX 1
-#define SIO_RESET_PURGE_TX 2
+#define SIO_RESET_PURGE_TX 1
+#define SIO_RESET_PURGE_RX 2
this change puzzles me. I've searched for my original USB "API documentation"
received under NDA in 2003 and it specifies these control values:

0: Reset SIO
1: Purge RX buffer
2: Purge TX buffer.


Did you run your tests only with the FT4232 type chips?

Also you mention the purge doesn't work correctly,
even after fixing it?

I guess there's an equivalent purge function in D2XX,
it might make sense to take a look either at the sent USB URBs
or I might even disassemble the purge function of it.
(which is legal in Germany as long as it's to ensure compatibility)

Cheers,
Thomas


--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+***@developer.intra2net.com
Eric L. Schott
2017-04-21 20:19:16 UTC
Permalink
On Friday, 21 Mar 2017 18:23:38 +0200, Thomas Jarosch
Post by Thomas Jarosch
thanks for your patch! Some questions below.
Post by Eric Schott
The provided patch is at the user's risk.
No licensing of this patch can preclude its use by the governement of
the United States or The Applied Research Laboratory of The
Pennsylvania State University.
would you be ok with licensing the purge_test.c code
as GPL v2 like the other example codes?
That would still fulfill your "license requirement" above.
Yes. This is fine. I included text as directed by my supervisor. The
GPL is a difficult concept.
Post by Thomas Jarosch
Perhaps it's a good idea to split the purge fix,
the new example code and the C++ fixes into three (logical) commits.
I will do that.
Post by Thomas Jarosch
Post by Eric Schott
diff --git a/src/ftdi.h b/src/ftdi.h
index bb66c53..acc1869 100644
--- a/src/ftdi.h
+++ b/src/ftdi.h
@@ -173,8 +173,8 @@ enum ftdi_module_detach_mode
#define SIO_RESET_SIO 0
-#define SIO_RESET_PURGE_RX 1
-#define SIO_RESET_PURGE_TX 2
+#define SIO_RESET_PURGE_TX 1
+#define SIO_RESET_PURGE_RX 2
this change puzzles me. I've searched for my original USB "API documentation"
0: Reset SIO
1: Purge RX buffer
2: Purge TX buffer.
I suspected you would be puzzled by the changes. I do not have
access to the NDA.

My desire was to as closely emulate the standard behavior of
the Linux serial port behavior of the ftdi_sio driver with respect
to purge (tcflush) and tcdrain functions. This is difficult based upon
the libftdi's different architecture (more on this shortly).

With the devices we control (e.g., GPS) consistent behavior is
important when needing to change baud rate or wait until all
data has been transmitted.

First, my observations of the Linux kernel with ftdi_sio driver

1. ftdi_sio never uses the SIO_RESET_PURGE definitions.

2. The kernel behavior for write: buffer the data and return
immediately. The driver outputs the buffered data in
background.

3. The kernel behavior for read is to always read data and
store into an internal buffer. The data is returned
immediately to the user application with the read.

The test program (with a loopback) does
* A write of a block of data
* A delay for 1/2 of the anticipated transmit interval
* Issue one of the three flush calls (read, write and both)
* Do a drain function for the remainder of the data to be
transmitted.
* Call the read function to obtain any buffered received data.

The Linux kernel behavior with all chips is
1 Read flush:
* The first 1/2 of the data is discarded (which was received)
* The drain function waits the remaining output data has been
sent out of the hardware.
* The read returns the second half of the data
2 Write flush:
* The second have the data (in kernel buffers) is discarded
* The drain returns immediately (since there is no data do
send)
* The read returns the first half of the data.
3 Read & Write flush
* The first half of the data (already buffered) is discarded
* The buffered output data is flushed
* The drain returns effectively immediately
* The read returns a handful of characters in the middle
of the message.

When using the Linux drivers, I have observed this (expected) behavior
with the test program with for the following
* 16550 UART (which has shallow hardware buffers)
* FT232 (which appears to have shallow hardware buffers)
* FT4232 (which has deep hardware buffers).

Returning to the promised discussion of libftdi's implementation
architecture: it basically does not have the background processing
as does the kernel. The standard read, write, and flush all
effectively perform hardware I/O via libusb. (This is somewhat of
a simplification. Please excuse me if I have some incorrectly
represented the library).

My observations with libftdi the FT4232 before swapping TX and RX
purge definitions was the read flush exhibited behavior of the Linux
write flush and the write flush exhibited the behavior of the
read flush. I found it difficult to characterize the behavior on
the FT232 chip.
Post by Thomas Jarosch
Did you run your tests only with the FT4232 type chips?
I performed tests on the hardware I had available (16650, FT232,
and FT4232). Obviously I could not use libftdi for the 16650.
Post by Thomas Jarosch
Also you mention the purge doesn't work correctly,
even after fixing it?
I was referring to the the FT232 chip only. The FT4232's deep
FIFOs make libftdi's purge functions work correctly
Post by Thomas Jarosch
I guess there's an equivalent purge function in D2XX,
it might make sense to take a look either at the sent USB URBs
or I might even disassemble the purge function of it.
(which is legal in Germany as long as it's to ensure compatibility)
I do not have the luxury of this. Please do as you see fit.

That includes being free to discard this patch if you feel it is not
in the community's best interest. I will not be offended. I will
continue to apply my patch. My desire in submitting the patch was to
aid other developers when they may encounter similar issues.

It will be short time before I rearrange the patches.

Best regards.
Eric.


--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+***@developer.intra2net.com
Thomas Jarosch
2017-05-23 19:19:45 UTC
Permalink
Hello Eric,
Post by Eric Schott
-#define SIO_RESET_PURGE_RX 1
-#define SIO_RESET_PURGE_TX 2
+#define SIO_RESET_PURGE_TX 1
+#define SIO_RESET_PURGE_RX 2
I've downloaded the d2xx driver from FTDI for the first time
and checked their header file: PURGE_RX is 1, PURGE_TX is 2.
So it's identical to libftdi.

FT_Purge() also behaves the same as libftdi,
at least as far as I can tell.

So I'm rather inclined to change the current behavior
as it might cause breakage for existing users of the lib.

If you are curious, you could also download the d2xx library
for your platform and experiment with the FT_Purge() function.

Cheers,
Thomas

--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+***@developer.intra2net.com
Russ Berman
2018-07-05 18:08:19 UTC
Permalink
I also have been having the same Purge issues as Eric. I also have the manual
from FTDI under NDA that Thomas referred to. I reached out to my FTDI
contact to discuss a possible PurgeRX/PurgeTX transposition in the manual,
and received the following reply:

/Likely an issue of naming. The buffers are named w/r/t the FT2xx chip.
When sending data from the FT2xx device to the host, the TX buffer is used.
(FT_Read command on host)
When the FT2xx device is receiving data from the host, the RX buffer is
used. (FT_Write command on host)
/

So it appears Eric's patch is correct and should be incorporated. It amazes
me that so many people have been using Libftdi up to this point without
experiencing (or at least complaining) about this problem. It's a killer for
us.

Best, -Russ



--
Sent from: http://libftdi.141977.n3.nabble.com/

--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+***@developer.intra2net.com
Eric Schott
2018-07-06 13:07:28 UTC
Permalink
Post by Russ Berman
I also have been having the same Purge issues as Eric. I also have the manual
from FTDI under NDA that Thomas referred to. I reached out to my FTDI
contact to discuss a possible PurgeRX/PurgeTX transposition in the manual,
/Likely an issue of naming. The buffers are named w/r/t the FT2xx chip.
When sending data from the FT2xx device to the host, the TX buffer is used.
(FT_Read command on host)
When the FT2xx device is receiving data from the host, the RX buffer is
used. (FT_Write command on host > /
Russ, Thank you for this information. You have independently verified
what I surmised after a two week or so effort of characterizing the
libftdi1 behavior and comparing it to a conventional UART.

The libftdi1 purge, as it exists, is broken code. Specifically an
RX purge clears the hardware TX buffers and flushes the software RX
buffer. The TX purge clears the hardware RX buffer and flushes the
software TX buffer.
Post by Russ Berman
So it appears Eric's patch is correct and should be incorporated. It amazes
me that so many people have been using Libftdi up to this point without
experiencing (or at least complaining) about this problem. It's a killer for
us.
I suspect individuals who have required a correct purse (flush) worked
around the broken code with either delays or discarding data.

Thomas Jarosch had issues with the patch because "it might cause
breakage for existing users of the lib."

Since my user set, while of a moderate size, is rather contained, I
implemented a "patched" libftd1 which had correct functionality.
Of course, the code compiled against my patch will not work with a
distribution supplied libftdi1.

At this point, I feel it would be beneficial to create a correctly
working library with an incremented major number with that fix.
At the same time, I recommend implementing API changes to minimize
breakage of user code with future versions (e.g., using a PIMPL
idiom for the context structure).

Eric.




--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+***@developer.intra2net.com
Thomas Jarosch
2018-07-06 13:13:49 UTC
Permalink
Post by Eric Schott
Thomas Jarosch had issues with the patch because "it might cause
breakage for existing users of the lib."
Since my user set, while of a moderate size, is rather contained, I
implemented a "patched" libftd1 which had correct functionality.
Of course, the code compiled against my patch will not work with a
distribution supplied libftdi1.
At this point, I feel it would be beneficial to create a correctly
working library with an incremented major number with that fix.
At the same time, I recommend implementing API changes to minimize
breakage of user code with future versions (e.g., using a PIMPL
idiom for the context structure).
breaking existing apps is still my main concern.

What could work: Implement a new API function with the correct behavior
and keep the old one around. Existing applications continue to work
and we could put a big fat warning in the code to use the new API.

Cheers,
Thomas




--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+***@developer.intra2net.com
Russ Berman
2018-07-06 18:19:42 UTC
Permalink
Keeping the old API around and adding new methods for PurgeRX and PurgeTX is
the right approach. I concur that this merits a major rev and clear
documentation that the old methods are deprecated.



--
Sent from: http://libftdi.141977.n3.nabble.com/

--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+***@developer.intra2net.com
Eric L. Schott
2018-10-18 15:20:24 UTC
Permalink
Post by Thomas Jarosch
Post by Eric Schott
Thomas Jarosch had issues with the patch because "it might cause
breakage for existing users of the lib."
Since my user set, while of a moderate size, is rather contained, I
implemented a "patched" libftd1 which had correct functionality.
Of course, the code compiled against my patch will not work with a
distribution supplied libftdi1.
At this point, I feel it would be beneficial to create a correctly
working library with an incremented major number with that fix.
At the same time, I recommend implementing API changes to minimize
breakage of user code with future versions (e.g., using a PIMPL
idiom for the context structure).
breaking existing apps is still my main concern.
What could work: Implement a new API function with the correct behavior
and keep the old one around. Existing applications continue to work
and we could put a big fat warning in the code to use the new API.
I have completed a patch which deprecates the purge functions and
introduces four correctly coded flush functions. I have chosen
function names which mimic the POSIX flush paradigm.

Jacob, the patch has a usage statement required by my employer (who
does not understand GPL. You may remove it when applying the patch.

This patch will be sent with my next email. Please let me know if
the lines are wrapped incorrectly by my mailer.

Eric.




--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+***@developer.intra2net.com
Eric L. Schott
2018-10-18 15:20:33 UTC
Permalink
The libFTDI implementation of the purge functionality is incorrect
because the library's authors understanding of the perspective of the
SIO_RESET_PURGE_TX and SIO_RESET_PURGE_RX was the opposite of the
vendor's documentation. That is, the library authors viewed purge TX
as purging data sent from the CPU through the FTDI chip to the
attached serial device. The vendor viewed purge TX from the chip's
perspective as data received from the attached serial device and
transmitted through the FTDI chip to the CPU.

In order to maintain the legacy API, the old functions are now marked
as deprecated and new functions are introduced. The mapping is
Deprecated function Replacement function
------------------------ ----------------------
ftdi_usb_purge_rx_buffer ftdi_tciflush
ftdi_usb_purge_tx_buffer ftdi_tcoflush
ftdi_usb_purge_buffers ftdi_tcioflush
Ftdi::Context::flush Ftdi::Context::tcflush

The provided patch is at the user's risk. No licensing of this patch can
preclude its use by the government of the United States or The
Applied Research Laboratory of The Pennsylvania State University.
---
doc/Doxyfile.in | 6 ++--
examples/async.c | 4 +--
ftdipp/ftdi.cpp | 27 ++++++++++++++
ftdipp/ftdi.hpp | 3 +-
src/ftdi.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++
src/ftdi.h | 58 +++++++++++++++++++++++++++---
src/ftdi_stream.c | 4 +--
7 files changed, 182 insertions(+), 12 deletions(-)

diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
index 84006c8..a4f59ee 100644
--- a/doc/Doxyfile.in
+++ b/doc/Doxyfile.in
@@ -1965,7 +1965,7 @@ ENABLE_PREPROCESSING = YES
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.

-MACRO_EXPANSION = NO
+MACRO_EXPANSION = YES

# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to
YES then
# the macro expansion is limited to the macros specified with the
PREDEFINED and
@@ -1973,7 +1973,7 @@ MACRO_EXPANSION = NO
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.

-EXPAND_ONLY_PREDEF = NO
+EXPAND_ONLY_PREDEF = YES

# If the SEARCH_INCLUDES tag is set to YES, the include files in the
# INCLUDE_PATH will be searched if a #include is found.
@@ -2005,7 +2005,7 @@ INCLUDE_FILE_PATTERNS =
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.

-PREDEFINED = LIBFTDI_LINUX_ASYNC_MODE
+PREDEFINED = LIBFTDI_LINUX_ASYNC_MODE=

# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES
then this
# tag can be used to specify a list of macro names that should be
expanded. The
diff --git a/examples/async.c b/examples/async.c
index 0589479..18989c1 100644
--- a/examples/async.c
+++ b/examples/async.c
@@ -93,9 +93,9 @@ int main(int argc, char **argv)
goto do_deinit;
}
ftdi_list_free(&devlist);
- int err = ftdi_usb_purge_buffers(ftdi);
+ int err = ftdi_tcioflush(ftdi);
if (err != 0) {
- fprintf(stderr, "ftdi_usb_purge_buffer: %d: %s\n",
+ fprintf(stderr, "ftdi_tcioflush: %d: %s\n",
err, ftdi_get_error_string(ftdi));
retval = -1;
goto do_deinit;
diff --git a/ftdipp/ftdi.cpp b/ftdipp/ftdi.cpp
index 7bf4ca6..dd777be 100644
--- a/ftdipp/ftdi.cpp
+++ b/ftdipp/ftdi.cpp
@@ -27,6 +27,7 @@ This exception does not invalidate any other reasons
why a work based
on this file might be covered by the GNU General Public License.
*/
#include <libusb.h>
+#define _FTDI_DISABLE_DEPRECATED
#include "ftdi.hpp"
#include "ftdi_i.h"
#include "ftdi.h"
@@ -168,6 +169,32 @@ int Context::flush(int mask)
return ret;
}

+int Context::tcflush(int mask)
+{
+ int ret;
+
+ switch (mask & (Input | Output)) {
+ case Input:
+ ret = ftdi_tciflush(d->ftdi);
+ break;
+
+ case Output:
+ ret = ftdi_tcoflush(d->ftdi);
+ break;
+
+ case Input | Output:
+ ret = ftdi_tcioflush(d->ftdi);
+ break;
+
+ default:
+ // Emulate behavior of previous version.
+ ret = 1;
+ break;
+ }
+
+ return ret;
+}
+
int Context::set_interface(enum ftdi_interface interface)
{
return ftdi_set_interface(d->ftdi, interface);
diff --git a/ftdipp/ftdi.hpp b/ftdipp/ftdi.hpp
index 2289a84..a5ede3c 100644
--- a/ftdipp/ftdi.hpp
+++ b/ftdipp/ftdi.hpp
@@ -85,7 +85,8 @@ public:
int open(const std::string& description);
int close();
int reset();
- int flush(int mask = Input|Output);
+ int DEPRECATED(flush)(int mask = Input|Output);
+ int tcflush(int mask = Input|Output);
int set_interface(enum ftdi_interface interface);
void set_usb_device(struct libusb_device_handle *dev);

diff --git a/src/ftdi.c b/src/ftdi.c
index 52266d0..155a770 100644
--- a/src/ftdi.c
+++ b/src/ftdi.c
@@ -35,6 +35,8 @@
#include <stdlib.h>

#include "ftdi_i.h"
+/* Prevent deprecated messages when building library */
+#define _FTDI_DISABLE_DEPRECATED
#include "ftdi.h"
#include "ftdi_version_i.h"

@@ -1016,6 +1018,7 @@ int ftdi_usb_reset(struct ftdi_context *ftdi)

/**
Clears the read buffer on the chip and the internal read buffer.
+ This is the correct behavior for an RX flush.

\param ftdi pointer to ftdi_context

@@ -1023,6 +1026,36 @@ int ftdi_usb_reset(struct ftdi_context *ftdi)
\retval -1: read buffer purge failed
\retval -2: USB device unavailable
*/
+int ftdi_tciflush(struct ftdi_context *ftdi)
+{
+ if (ftdi == NULL || ftdi->usb_dev == NULL)
+ ftdi_error_return(-2, "USB device unavailable");
+
+ if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
+ SIO_RESET_REQUEST, SIO_TCIFLUSH,
+ ftdi->index, NULL, 0,
ftdi->usb_write_timeout) < 0)
+ ftdi_error_return(-1, "FTDI purge of RX buffer failed");
+
+ // Invalidate data in the readbuffer
+ ftdi->readbuffer_offset = 0;
+ ftdi->readbuffer_remaining = 0;
+
+ return 0;
+}
+
+
+/**
+ Clears the write buffer on the chip and the internal read buffer.
+ This is incorrect behavior for an RX flush.
+
+ \param ftdi pointer to ftdi_context
+
+ \retval 0: all fine
+ \retval -1: write buffer purge failed
+ \retval -2: USB device unavailable
+
+ \deprecated Use \ref ftdi_tciflush(struct ftdi_context *ftdi)
+*/
int ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi)
{
if (ftdi == NULL || ftdi->usb_dev == NULL)
@@ -1042,6 +1075,7 @@ int ftdi_usb_purge_rx_buffer(struct ftdi_context
*ftdi)

/**
Clears the write buffer on the chip.
+ This is correct behavior for a TX flush.

\param ftdi pointer to ftdi_context

@@ -1049,6 +1083,32 @@ int ftdi_usb_purge_rx_buffer(struct ftdi_context
*ftdi)
\retval -1: write buffer purge failed
\retval -2: USB device unavailable
*/
+int ftdi_tcoflush(struct ftdi_context *ftdi)
+{
+ if (ftdi == NULL || ftdi->usb_dev == NULL)
+ ftdi_error_return(-2, "USB device unavailable");
+
+ if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
+ SIO_RESET_REQUEST, SIO_TCOFLUSH,
+ ftdi->index, NULL, 0,
ftdi->usb_write_timeout) < 0)
+ ftdi_error_return(-1, "FTDI purge of TX buffer failed");
+
+ return 0;
+}
+
+
+/**
+ Clears the read buffer on the chip.
+ This is incorrect behavior for a TX flush.
+
+ \param ftdi pointer to ftdi_context
+
+ \retval 0: all fine
+ \retval -1: read buffer purge failed
+ \retval -2: USB device unavailable
+
+ \deprecated Use \ref ftdi_tcoflush(struct ftdi_context *ftdi)
+*/
int ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi)
{
if (ftdi == NULL || ftdi->usb_dev == NULL)
@@ -1062,8 +1122,38 @@ int ftdi_usb_purge_tx_buffer(struct ftdi_context
*ftdi)
return 0;
}

+/**
+ Clears the RX and TX FIFOs on the chip and the internal read buffer.
+ This is correct behavior for both RX and TX flush.
+
+ \param ftdi pointer to ftdi_context
+
+ \retval 0: all fine
+ \retval -1: read buffer purge failed
+ \retval -2: write buffer purge failed
+ \retval -3: USB device unavailable
+*/
+int ftdi_tcioflush(struct ftdi_context *ftdi)
+{
+ int result;
+
+ if (ftdi == NULL || ftdi->usb_dev == NULL)
+ ftdi_error_return(-3, "USB device unavailable");
+
+ result = ftdi_tcoflush(ftdi);
+ if (result < 0)
+ return -1;
+
+ result = ftdi_tciflush(ftdi);
+ if (result < 0)
+ return -2;
+
+ return 0;
+}
+
/**
Clears the buffers on the chip and the internal read buffer.
+ While coded incorrectly, the result is satisfactory,

\param ftdi pointer to ftdi_context

@@ -1071,6 +1161,8 @@ int ftdi_usb_purge_tx_buffer(struct ftdi_context
*ftdi)
\retval -1: read buffer purge failed
\retval -2: write buffer purge failed
\retval -3: USB device unavailable
+
+ \deprecated Use \ref ftdi_tcioflush(struct ftdi_context *ftdi)
*/
int ftdi_usb_purge_buffers(struct ftdi_context *ftdi)
{
diff --git a/src/ftdi.h b/src/ftdi.h
index f170881..d740617 100644
--- a/src/ftdi.h
+++ b/src/ftdi.h
@@ -22,6 +22,12 @@
#include <sys/time.h>
#endif

+#ifdef _FTDI_DISABLE_DEPRECATED
+#define _Ftdi_Pragma(_msg)
+#else
+#define _Ftdi_Pragma(_msg) _Pragma(_msg)
+#endif
+
/* 'interface' might be defined as a macro on Windows, so we need to
* undefine it so as not to break the current libftdi API, because
* struct ftdi_context has an 'interface' member
@@ -174,8 +180,45 @@ enum ftdi_module_detach_mode


#define SIO_RESET_SIO 0
+
+/* ** WARNING ** SIO_RESET_PURGE_RX or SIO_RESET_PURGE_TX are values used
+ * internally by libftdi to purge the RX and/or TX FIFOs (buffers).
+ * APPLICATION PROGRAMS SHOULD NOT BE USING THESE VALUES. Application
+ * programs should use one of the ftdi_tciflush, ftdi_tcoflush, or
+ * ftdi_tcioflush functions which emulate the Linux serial port tcflush(3)
+ * function.
+ *
+ * History:
+ *
+ * The defintions for these values are with respect to the FTDI chip,
not the
+ * CPU. That is, when the FTDI chip receives a USB control transfer
request
+ * with the command SIO_RESET_PURGE_RX, the FTDI chip empties the FIFO
+ * containing data received from the CPU awaiting tranfer out the serial
+ * port to the connected serial device (e.g., a modem). Likewise, upon
+ * reception of the SIO_RESET_PURGE_TX command, the FTDI chip empties the
+ * FIFO of data received from the attached serial device destined to be
+ * transmitted to the CPU.
+ *
+ * Unfortunately the coding of the previous releases of libfti assumed
these
+ * commands had the opposite effect. This resulted in the function
+ * ftdi_usb_purge_tx_buffer clearing data received from the attached serial
+ * device. Similarly, the function ftdi_usb_purge_rx_buffer cleared the
+ * FTDI FIFO containing data to be transmitted to the attached serial
+ * device. More seriously, this latter function clear the libftid's
+ * internal buffer of data received from the serial device, destined
+ * to the application program.
+ */
+#ifdef __GNUC__
+#define SIO_RESET_PURGE_RX _Ftdi_Pragma("GCC warning
\"SIO_RESET_PURGE_RX\" deprecated: - use tciflush() method") 1
+#define SIO_RESET_PURGE_TX _Ftdi_Pragma("GCC warning
\"SIO_RESET_PURGE_RX\" deprecated: - use tcoflush() method") 2
+#else
+#pragma message("WARNING: You need to implement deprecated #define for
this compiler")
#define SIO_RESET_PURGE_RX 1
#define SIO_RESET_PURGE_TX 2
+#endif
+/* New names for the values used internally to flush (purge). */
+#define SIO_TCIFLUSH 2
+#define SIO_TCOFLUSH 1

#define SIO_DISABLE_FLOW_CTRL 0x0
#define SIO_RTS_CTS_HS (0x1 << 8)
@@ -195,14 +238,18 @@ enum ftdi_module_detach_mode
(taken from libusb) */
#define FTDI_URB_USERCONTEXT_COOKIE ((void *)0x1)

+#ifdef _FTDI_DISABLE_DEPRECATED
+#define DEPRECATED(func) func
+#else
#ifdef __GNUC__
-#define DEPRECATED(func) func __attribute__ ((deprecated))
+#define DEPRECATED(func) __attribute__ ((deprecated)) func
#elif defined(_MSC_VER)
#define DEPRECATED(func) __declspec(deprecated) func
#else
#pragma message("WARNING: You need to implement DEPRECATED for this
compiler")
#define DEPRECATED(func) func
#endif
+#endif

struct ftdi_transfer_control
{
@@ -509,9 +556,12 @@ extern "C"

int ftdi_usb_close(struct ftdi_context *ftdi);
int ftdi_usb_reset(struct ftdi_context *ftdi);
- int ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi);
- int ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi);
- int ftdi_usb_purge_buffers(struct ftdi_context *ftdi);
+ int ftdi_tciflush(struct ftdi_context *ftdi);
+ int ftdi_tcoflush(struct ftdi_context *ftdi);
+ int ftdi_tcioflush(struct ftdi_context *ftdi);
+ int DEPRECATED(ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi));
+ int DEPRECATED(ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi));
+ int DEPRECATED(ftdi_usb_purge_buffers(struct ftdi_context *ftdi));

int ftdi_set_baudrate(struct ftdi_context *ftdi, int baudrate);
int ftdi_set_line_property(struct ftdi_context *ftdi, enum
ftdi_bits_type bits,
diff --git a/src/ftdi_stream.c b/src/ftdi_stream.c
index 1dc46ea..75f1ace 100644
--- a/src/ftdi_stream.c
+++ b/src/ftdi_stream.c
@@ -172,9 +172,9 @@ ftdi_readstream(struct ftdi_context *ftdi,
}

/* Purge anything remaining in the buffers*/
- if (ftdi_usb_purge_buffers(ftdi) < 0)
+ if (ftdi_tcioflush(ftdi) < 0)
{
- fprintf(stderr,"Can't Purge\n");
+ fprintf(stderr,"Can't flush FIFOs & buffers\n");
return 1;
}
--
2.17.1


--
libftdi - see http://www.intra2net.com/en/developer/libftdi for details.
To unsubscribe send a mail to libftdi+***@developer.intra2net.com
Loading...