Skip to content

Commit ed46f09

Browse files
Eric Schottthomasjfox
authored andcommitted
Implement tc[io]flush methods & deprecate broken purge_buffers methods.
The definitions for the SIO_RESET_PURGE_RX or SIO_RESET_PURGE_TX 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 transfer 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. This patch adds the ftdi_tciflush, ftdi_tcoflush, and ftdi_tcioflush functions which emulate the Linux serial port tcflush(3) function.
1 parent bfbd47b commit ed46f09

File tree

6 files changed

+180
-9
lines changed

6 files changed

+180
-9
lines changed

examples/async.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@ int main(int argc, char **argv)
9393
goto do_deinit;
9494
}
9595
ftdi_list_free(&devlist);
96-
int err = ftdi_usb_purge_buffers(ftdi);
96+
int err = ftdi_tcioflush(ftdi);
9797
if (err != 0) {
98-
fprintf(stderr, "ftdi_usb_purge_buffer: %d: %s\n",
98+
fprintf(stderr, "ftdi_tcioflush: %d: %s\n",
9999
err, ftdi_get_error_string(ftdi));
100100
retval = -1;
101101
goto do_deinit;

ftdipp/ftdi.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ This exception does not invalidate any other reasons why a work based
2727
on this file might be covered by the GNU General Public License.
2828
*/
2929
#include <libusb.h>
30+
#define _FTDI_DISABLE_DEPRECATED
3031
#include "ftdi.hpp"
3132
#include "ftdi_i.h"
3233
#include "ftdi.h"
@@ -168,6 +169,32 @@ int Context::flush(int mask)
168169
return ret;
169170
}
170171

172+
int Context::tcflush(int mask)
173+
{
174+
int ret;
175+
176+
switch (mask & (Input | Output)) {
177+
case Input:
178+
ret = ftdi_tciflush(d->ftdi);
179+
break;
180+
181+
case Output:
182+
ret = ftdi_tcoflush(d->ftdi);
183+
break;
184+
185+
case Input | Output:
186+
ret = ftdi_tcioflush(d->ftdi);
187+
break;
188+
189+
default:
190+
// Emulate behavior of previous version.
191+
ret = 1;
192+
break;
193+
}
194+
195+
return ret;
196+
}
197+
171198
int Context::set_interface(enum ftdi_interface interface)
172199
{
173200
return ftdi_set_interface(d->ftdi, interface);

ftdipp/ftdi.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ class Context
8585
int open(const std::string& description);
8686
int close();
8787
int reset();
88-
int flush(int mask = Input|Output);
88+
int DEPRECATED(flush)(int mask = Input|Output);
89+
int tcflush(int mask = Input|Output);
8990
int set_interface(enum ftdi_interface interface);
9091
void set_usb_device(struct libusb_device_handle *dev);
9192

src/ftdi.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
#include <stdlib.h>
3636

3737
#include "ftdi_i.h"
38+
/* Prevent deprecated messages when building library */
39+
#define _FTDI_DISABLE_DEPRECATED
3840
#include "ftdi.h"
3941
#include "ftdi_version_i.h"
4042

@@ -1016,13 +1018,44 @@ int ftdi_usb_reset(struct ftdi_context *ftdi)
10161018

10171019
/**
10181020
Clears the read buffer on the chip and the internal read buffer.
1021+
This is the correct behavior for an RX flush.
10191022
10201023
\param ftdi pointer to ftdi_context
10211024
10221025
\retval 0: all fine
10231026
\retval -1: read buffer purge failed
10241027
\retval -2: USB device unavailable
10251028
*/
1029+
int ftdi_tciflush(struct ftdi_context *ftdi)
1030+
{
1031+
if (ftdi == NULL || ftdi->usb_dev == NULL)
1032+
ftdi_error_return(-2, "USB device unavailable");
1033+
1034+
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
1035+
SIO_RESET_REQUEST, SIO_TCIFLUSH,
1036+
ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0)
1037+
ftdi_error_return(-1, "FTDI purge of RX buffer failed");
1038+
1039+
// Invalidate data in the readbuffer
1040+
ftdi->readbuffer_offset = 0;
1041+
ftdi->readbuffer_remaining = 0;
1042+
1043+
return 0;
1044+
}
1045+
1046+
1047+
/**
1048+
Clears the write buffer on the chip and the internal read buffer.
1049+
This is incorrect behavior for an RX flush.
1050+
1051+
\param ftdi pointer to ftdi_context
1052+
1053+
\retval 0: all fine
1054+
\retval -1: write buffer purge failed
1055+
\retval -2: USB device unavailable
1056+
1057+
\deprecated Use \ref ftdi_tciflush(struct ftdi_context *ftdi)
1058+
*/
10261059
int ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi)
10271060
{
10281061
if (ftdi == NULL || ftdi->usb_dev == NULL)
@@ -1042,13 +1075,40 @@ int ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi)
10421075

10431076
/**
10441077
Clears the write buffer on the chip.
1078+
This is correct behavior for a TX flush.
10451079
10461080
\param ftdi pointer to ftdi_context
10471081
10481082
\retval 0: all fine
10491083
\retval -1: write buffer purge failed
10501084
\retval -2: USB device unavailable
10511085
*/
1086+
int ftdi_tcoflush(struct ftdi_context *ftdi)
1087+
{
1088+
if (ftdi == NULL || ftdi->usb_dev == NULL)
1089+
ftdi_error_return(-2, "USB device unavailable");
1090+
1091+
if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
1092+
SIO_RESET_REQUEST, SIO_TCOFLUSH,
1093+
ftdi->index, NULL, 0, ftdi->usb_write_timeout) < 0)
1094+
ftdi_error_return(-1, "FTDI purge of TX buffer failed");
1095+
1096+
return 0;
1097+
}
1098+
1099+
1100+
/**
1101+
Clears the read buffer on the chip.
1102+
This is incorrect behavior for a TX flush.
1103+
1104+
\param ftdi pointer to ftdi_context
1105+
1106+
\retval 0: all fine
1107+
\retval -1: read buffer purge failed
1108+
\retval -2: USB device unavailable
1109+
1110+
\deprecated Use \ref ftdi_tcoflush(struct ftdi_context *ftdi)
1111+
*/
10521112
int ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi)
10531113
{
10541114
if (ftdi == NULL || ftdi->usb_dev == NULL)
@@ -1062,15 +1122,47 @@ int ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi)
10621122
return 0;
10631123
}
10641124

1125+
/**
1126+
Clears the RX and TX FIFOs on the chip and the internal read buffer.
1127+
This is correct behavior for both RX and TX flush.
1128+
1129+
\param ftdi pointer to ftdi_context
1130+
1131+
\retval 0: all fine
1132+
\retval -1: read buffer purge failed
1133+
\retval -2: write buffer purge failed
1134+
\retval -3: USB device unavailable
1135+
*/
1136+
int ftdi_tcioflush(struct ftdi_context *ftdi)
1137+
{
1138+
int result;
1139+
1140+
if (ftdi == NULL || ftdi->usb_dev == NULL)
1141+
ftdi_error_return(-3, "USB device unavailable");
1142+
1143+
result = ftdi_tcoflush(ftdi);
1144+
if (result < 0)
1145+
return -1;
1146+
1147+
result = ftdi_tciflush(ftdi);
1148+
if (result < 0)
1149+
return -2;
1150+
1151+
return 0;
1152+
}
1153+
10651154
/**
10661155
Clears the buffers on the chip and the internal read buffer.
1156+
While coded incorrectly, the result is satisfactory.
10671157
10681158
\param ftdi pointer to ftdi_context
10691159
10701160
\retval 0: all fine
10711161
\retval -1: read buffer purge failed
10721162
\retval -2: write buffer purge failed
10731163
\retval -3: USB device unavailable
1164+
1165+
\deprecated Use \ref ftdi_tcioflush(struct ftdi_context *ftdi)
10741166
*/
10751167
int ftdi_usb_purge_buffers(struct ftdi_context *ftdi)
10761168
{

src/ftdi.h

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@
2222
#include <sys/time.h>
2323
#endif
2424

25+
/* Define _FTDI_DISABLE_DEPRECATED to disable deprecated messages. */
26+
#ifdef _FTDI_DISABLE_DEPRECATED
27+
#define _Ftdi_Pragma(_msg)
28+
#else
29+
#define _Ftdi_Pragma(_msg) _Pragma(_msg)
30+
#endif
31+
2532
/* 'interface' might be defined as a macro on Windows, so we need to
2633
* undefine it so as not to break the current libftdi API, because
2734
* struct ftdi_context has an 'interface' member
@@ -174,8 +181,45 @@ enum ftdi_module_detach_mode
174181

175182

176183
#define SIO_RESET_SIO 0
184+
185+
/* ** WARNING ** SIO_RESET_PURGE_RX or SIO_RESET_PURGE_TX are values used
186+
* internally by libftdi to purge the RX and/or TX FIFOs (buffers).
187+
* APPLICATION PROGRAMS SHOULD NOT BE USING THESE VALUES. Application
188+
* programs should use one of the ftdi_tciflush, ftdi_tcoflush, or
189+
* ftdi_tcioflush functions which emulate the Linux serial port tcflush(3)
190+
* function.
191+
*
192+
* History:
193+
*
194+
* The definitions for these values are with respect to the FTDI chip, not the
195+
* CPU. That is, when the FTDI chip receives a USB control transfer request
196+
* with the command SIO_RESET_PURGE_RX, the FTDI chip empties the FIFO
197+
* containing data received from the CPU awaiting transfer out the serial
198+
* port to the connected serial device (e.g., a modem). Likewise, upon
199+
* reception of the SIO_RESET_PURGE_TX command, the FTDI chip empties the
200+
* FIFO of data received from the attached serial device destined to be
201+
* transmitted to the CPU.
202+
*
203+
* Unfortunately the coding of the previous releases of libfti assumed these
204+
* commands had the opposite effect. This resulted in the function
205+
* ftdi_usb_purge_tx_buffer clearing data received from the attached serial
206+
* device. Similarly, the function ftdi_usb_purge_rx_buffer cleared the
207+
* FTDI FIFO containing data to be transmitted to the attached serial
208+
* device. More seriously, this latter function clear the libftid's
209+
* internal buffer of data received from the serial device, destined
210+
* to the application program.
211+
*/
212+
#ifdef __GNUC__
213+
#define SIO_RESET_PURGE_RX _Ftdi_Pragma("GCC warning \"SIO_RESET_PURGE_RX\" deprecated: - use tciflush() method") 1
214+
#define SIO_RESET_PURGE_TX _Ftdi_Pragma("GCC warning \"SIO_RESET_PURGE_RX\" deprecated: - use tcoflush() method") 2
215+
#else
216+
#pragma message("WARNING: You need to implement deprecated #define for this compiler")
177217
#define SIO_RESET_PURGE_RX 1
178218
#define SIO_RESET_PURGE_TX 2
219+
#endif
220+
/* New names for the values used internally to flush (purge). */
221+
#define SIO_TCIFLUSH 2
222+
#define SIO_TCOFLUSH 1
179223

180224
#define SIO_DISABLE_FLOW_CTRL 0x0
181225
#define SIO_RTS_CTS_HS (0x1 << 8)
@@ -195,14 +239,18 @@ enum ftdi_module_detach_mode
195239
(taken from libusb) */
196240
#define FTDI_URB_USERCONTEXT_COOKIE ((void *)0x1)
197241

242+
#ifdef _FTDI_DISABLE_DEPRECATED
243+
#define DEPRECATED(func) func
244+
#else
198245
#ifdef __GNUC__
199-
#define DEPRECATED(func) func __attribute__ ((deprecated))
246+
#define DEPRECATED(func) __attribute__ ((deprecated)) func
200247
#elif defined(_MSC_VER)
201248
#define DEPRECATED(func) __declspec(deprecated) func
202249
#else
203250
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
204251
#define DEPRECATED(func) func
205252
#endif
253+
#endif
206254

207255
struct ftdi_transfer_control
208256
{
@@ -509,9 +557,12 @@ extern "C"
509557

510558
int ftdi_usb_close(struct ftdi_context *ftdi);
511559
int ftdi_usb_reset(struct ftdi_context *ftdi);
512-
int ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi);
513-
int ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi);
514-
int ftdi_usb_purge_buffers(struct ftdi_context *ftdi);
560+
int ftdi_tciflush(struct ftdi_context *ftdi);
561+
int ftdi_tcoflush(struct ftdi_context *ftdi);
562+
int ftdi_tcioflush(struct ftdi_context *ftdi);
563+
int DEPRECATED(ftdi_usb_purge_rx_buffer(struct ftdi_context *ftdi));
564+
int DEPRECATED(ftdi_usb_purge_tx_buffer(struct ftdi_context *ftdi));
565+
int DEPRECATED(ftdi_usb_purge_buffers(struct ftdi_context *ftdi));
515566

516567
int ftdi_set_baudrate(struct ftdi_context *ftdi, int baudrate);
517568
int ftdi_set_line_property(struct ftdi_context *ftdi, enum ftdi_bits_type bits,

src/ftdi_stream.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,9 +172,9 @@ ftdi_readstream(struct ftdi_context *ftdi,
172172
}
173173

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

0 commit comments

Comments
 (0)