Browse Source

ft232r: Buffer writes to improve performance

This cuts bitstream uploads from 1 hour to 3 minutes
Luke Dashjr 13 years ago
parent
commit
e95d68e09e
2 changed files with 55 additions and 1 deletions
  1. 54 1
      ft232r.c
  2. 1 0
      ft232r.h

+ 54 - 1
ft232r.c

@@ -10,6 +10,7 @@
 #include <errno.h>
 #include <errno.h>
 #include <stdbool.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdint.h>
+#include <string.h>
 
 
 #include <libusb-1.0/libusb.h>
 #include <libusb-1.0/libusb.h>
 
 
@@ -151,6 +152,9 @@ struct ft232r_device_handle {
 	uint8_t o;
 	uint8_t o;
 	unsigned char ibuf[256];
 	unsigned char ibuf[256];
 	int ibufLen;
 	int ibufLen;
+	uint16_t osz;
+	unsigned char *obuf;
+	uint16_t obufsz;
 };
 };
 
 
 struct ft232r_device_handle *ft232r_open(libusb_device *dev)
 struct ft232r_device_handle *ft232r_open(libusb_device *dev)
@@ -193,6 +197,8 @@ struct ft232r_device_handle *ft232r_open(libusb_device *dev)
 	}
 	}
 	ftdi->i = altcfg->endpoint[0].bEndpointAddress;
 	ftdi->i = altcfg->endpoint[0].bEndpointAddress;
 	ftdi->o = altcfg->endpoint[1].bEndpointAddress;
 	ftdi->o = altcfg->endpoint[1].bEndpointAddress;
+	ftdi->osz = altcfg->endpoint[1].wMaxPacketSize;
+	ftdi->obuf = malloc(ftdi->osz);
 	libusb_free_config_descriptor(cfg);
 	libusb_free_config_descriptor(cfg);
 
 
 	return ftdi;
 	return ftdi;
@@ -218,6 +224,8 @@ bool ft232r_purge_buffers(struct ft232r_device_handle *dev, enum ft232r_reset_pu
 
 
 bool ft232r_set_bitmode(struct ft232r_device_handle *dev, uint8_t mask, uint8_t mode)
 bool ft232r_set_bitmode(struct ft232r_device_handle *dev, uint8_t mask, uint8_t mode)
 {
 {
+	if (ft232r_flush(dev) < 0)
+		return false;
 	if (libusb_control_transfer(dev->h, FTDI_REQTYPE_OUT, FTDI_REQUEST_SET_BITMODE, mask, FTDI_INDEX, NULL, 0, FTDI_TIMEOUT))
 	if (libusb_control_transfer(dev->h, FTDI_REQTYPE_OUT, FTDI_REQUEST_SET_BITMODE, mask, FTDI_INDEX, NULL, 0, FTDI_TIMEOUT))
 		return false;
 		return false;
 	return !libusb_control_transfer(dev->h, FTDI_REQTYPE_OUT, FTDI_REQUEST_SET_BITMODE, (mode << 8) | mask, FTDI_INDEX, NULL, 0, FTDI_TIMEOUT);
 	return !libusb_control_transfer(dev->h, FTDI_REQTYPE_OUT, FTDI_REQUEST_SET_BITMODE, (mode << 8) | mask, FTDI_INDEX, NULL, 0, FTDI_TIMEOUT);
@@ -240,9 +248,47 @@ static ssize_t ft232r_readwrite(struct ft232r_device_handle *dev, unsigned char
 	}
 	}
 }
 }
 
 
+ssize_t ft232r_flush(struct ft232r_device_handle *dev)
+{
+	if (!dev->obufsz)
+		return 0;
+	ssize_t r = ft232r_readwrite(dev, dev->o, dev->obuf, dev->obufsz);
+	if (r == dev->obufsz) {
+		dev->obufsz = 0;
+	} else if (r > 0) {
+		dev->obufsz -= r;
+		memmove(dev->obuf, &dev->obuf[r], dev->obufsz);
+	}
+	return r;
+}
+
 ssize_t ft232r_write(struct ft232r_device_handle *dev, void *data, size_t count)
 ssize_t ft232r_write(struct ft232r_device_handle *dev, void *data, size_t count)
 {
 {
-	return ft232r_readwrite(dev, dev->o, data, count);
+	uint16_t bufleft;
+	ssize_t r;
+	
+	bufleft = dev->osz - dev->obufsz;
+	
+	if (count < bufleft) {
+		// Just add to output buffer
+		memcpy(&dev->obuf[dev->obufsz], data, count);
+		dev->obufsz += count;
+		return count;
+	}
+	
+	// Fill up buffer and flush
+	memcpy(&dev->obuf[dev->obufsz], data, bufleft);
+	dev->obufsz += bufleft;
+	r = ft232r_flush(dev);
+	
+	if (unlikely(r <= 0)) {
+		// In this case, no bytes were written supposedly, so remove this data from buffer
+		dev->obufsz -= bufleft;
+		return r;
+	}
+	
+	// Even if not all <bufleft> bytes from this write got out, the remaining are still buffered
+	return bufleft;
 }
 }
 
 
 typedef ssize_t (*ft232r_rwfunc_t)(struct ft232r_device_handle *, void*, size_t);
 typedef ssize_t (*ft232r_rwfunc_t)(struct ft232r_device_handle *, void*, size_t);
@@ -267,6 +313,13 @@ ssize_t ft232r_write_all(struct ft232r_device_handle *dev, void *data, size_t co
 
 
 ssize_t ft232r_read(struct ft232r_device_handle *dev, void *data, size_t count)
 ssize_t ft232r_read(struct ft232r_device_handle *dev, void *data, size_t count)
 {
 {
+	ssize_t r;
+	
+	// Flush any pending output before reading
+	r = ft232r_flush(dev);
+	if (r < 0)
+		return r;
+	
 	// First 2 bytes are FTDI status or something
 	// First 2 bytes are FTDI status or something
 	while (dev->ibufLen <= 2) {
 	while (dev->ibufLen <= 2) {
 		// TODO: Implement a timeout for status byte repeating
 		// TODO: Implement a timeout for status byte repeating

+ 1 - 0
ft232r.h

@@ -32,6 +32,7 @@ extern struct ft232r_device_handle *ft232r_open(libusb_device *);
 extern void ft232r_close(struct ft232r_device_handle *);
 extern void ft232r_close(struct ft232r_device_handle *);
 extern bool ft232r_purge_buffers(struct ft232r_device_handle *, enum ft232r_reset_purge);
 extern bool ft232r_purge_buffers(struct ft232r_device_handle *, enum ft232r_reset_purge);
 extern bool ft232r_set_bitmode(struct ft232r_device_handle *, uint8_t mask, uint8_t mode);
 extern bool ft232r_set_bitmode(struct ft232r_device_handle *, uint8_t mask, uint8_t mode);
+extern ssize_t ft232r_flush(struct ft232r_device_handle *);
 extern ssize_t ft232r_write(struct ft232r_device_handle *, void *data, size_t count);
 extern ssize_t ft232r_write(struct ft232r_device_handle *, void *data, size_t count);
 extern ssize_t ft232r_write_all(struct ft232r_device_handle *, void *data, size_t count);
 extern ssize_t ft232r_write_all(struct ft232r_device_handle *, void *data, size_t count);
 extern ssize_t ft232r_read(struct ft232r_device_handle *, void *buf, size_t count);
 extern ssize_t ft232r_read(struct ft232r_device_handle *, void *buf, size_t count);