1
0
mirror of https://github.com/mik3y/usb-serial-for-android synced 2025-06-10 17:36:21 +00:00

Increase default read/write buffer sizes; allow tuning.

This commit is contained in:
mike wakerly 2012-10-11 19:40:54 -07:00
parent c5e9955b01
commit b328f3cbc9
3 changed files with 123 additions and 64 deletions

View File

@ -1,7 +1,6 @@
package com.hoho.android.usbserial.driver; package com.hoho.android.usbserial.driver;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
@ -21,8 +20,6 @@ public class CdcAcmSerialDriver extends UsbSerialDriver {
private final String TAG = CdcAcmSerialDriver.class.getSimpleName(); private final String TAG = CdcAcmSerialDriver.class.getSimpleName();
private final byte[] mReadBuffer = new byte[4096];
private UsbInterface mControlInterface; private UsbInterface mControlInterface;
private UsbInterface mDataInterface; private UsbInterface mDataInterface;
@ -96,47 +93,55 @@ public class CdcAcmSerialDriver extends UsbSerialDriver {
@Override @Override
public int read(byte[] dest, int timeoutMillis) throws IOException { public int read(byte[] dest, int timeoutMillis) throws IOException {
int readAmt = Math.min(dest.length, mReadBuffer.length); final int numBytesRead;
readAmt = Math.min(readAmt, mReadEndpoint.getMaxPacketSize()); synchronized (mReadBufferLock) {
final int transferred = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt, int readAmt = Math.min(dest.length, mReadBuffer.length);
timeoutMillis); readAmt = Math.min(readAmt, mReadEndpoint.getMaxPacketSize());
numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
if (transferred < 0) { timeoutMillis);
// This sucks: we get -1 on timeout, not 0 as preferred. if (numBytesRead < 0) {
// We *should* use UsbRequest, except it has a bug/api oversight // This sucks: we get -1 on timeout, not 0 as preferred.
// where there is no way to determine the number of bytes read // We *should* use UsbRequest, except it has a bug/api oversight
// in response :\ -- http://b.android.com/28023 // where there is no way to determine the number of bytes read
return 0; // in response :\ -- http://b.android.com/28023
return 0;
}
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
} }
System.arraycopy(mReadBuffer, 0, dest, 0, transferred); return numBytesRead;
return transferred;
} }
@Override @Override
public int write(byte[] src, int timeoutMillis) throws IOException { public int write(byte[] src, int timeoutMillis) throws IOException {
// TODO(mikey): Nearly identical to FtdiSerial write. Refactor.
int offset = 0; int offset = 0;
final int chunksize = mWriteEndpoint.getMaxPacketSize();
while (offset < src.length) { while (offset < src.length) {
final byte[] writeBuffer;
final int writeLength; final int writeLength;
final int amtWritten;
// bulkTransfer does not support offsets; make a copy if necessary. synchronized (mWriteBufferLock) {
writeLength = Math.min(src.length - offset, chunksize); final byte[] writeBuffer;
if (offset == 0) {
writeBuffer = src; writeLength = Math.min(src.length - offset, mWriteBuffer.length);
} else { if (offset == 0) {
writeBuffer = Arrays.copyOfRange(src, offset, offset + writeLength); writeBuffer = src;
} else {
// bulkTransfer does not support offsets, make a copy.
System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
writeBuffer = mWriteBuffer;
}
amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength,
timeoutMillis);
} }
if (amtWritten <= 0) {
final int amt = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength,
timeoutMillis);
if (amt <= 0) {
throw new IOException("Error writing " + writeLength throw new IOException("Error writing " + writeLength
+ " bytes at offset " + offset + " length=" + src.length); + " bytes at offset " + offset + " length=" + src.length);
} }
Log.d(TAG, "Wrote amt=" + amt + " attempted=" + writeBuffer.length);
offset += amt; Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength);
offset += amtWritten;
} }
return offset; return offset;
} }

View File

@ -22,7 +22,6 @@ package com.hoho.android.usbserial.driver;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
@ -38,8 +37,8 @@ import com.hoho.android.usbserial.util.HexDump;
/** /**
* A {@link UsbSerialDriver} implementation for a variety of FTDI devices * A {@link UsbSerialDriver} implementation for a variety of FTDI devices
* <p> * <p>
* This driver is based on <a * This driver is based on
* href="http://www.intra2net.com/en/developer/libftdi">libftdi</a>, and is * <a href="http://www.intra2net.com/en/developer/libftdi">libftdi</a>, and is
* copyright and subject to the following terms: * copyright and subject to the following terms:
* *
* <pre> * <pre>
@ -142,11 +141,6 @@ public class FtdiSerialDriver extends UsbSerialDriver {
public static final int FTDI_DEVICE_IN_REQTYPE = public static final int FTDI_DEVICE_IN_REQTYPE =
UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN; UsbConstants.USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN;
/**
* Size of chunks, used in {@link #write(byte[], int)}.
*/
private static final int WRITE_CHUNKSIZE = 4096;
/** /**
* Length of the modem status header, transmitted with every read. * Length of the modem status header, transmitted with every read.
*/ */
@ -156,8 +150,6 @@ public class FtdiSerialDriver extends UsbSerialDriver {
private DeviceType mType; private DeviceType mType;
private final byte[] mReadBuffer = new byte[4096];
/** /**
* FTDI chip types. * FTDI chip types.
*/ */
@ -228,10 +220,15 @@ public class FtdiSerialDriver extends UsbSerialDriver {
@Override @Override
public int read(byte[] dest, int timeoutMillis) throws IOException { public int read(byte[] dest, int timeoutMillis) throws IOException {
final int readAmt = Math.min(dest.length, mReadBuffer.length);
final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(0); final UsbEndpoint endpoint = mDevice.getInterface(0).getEndpoint(0);
if (ENABLE_ASYNC_READS) { if (ENABLE_ASYNC_READS) {
final int readAmt;
synchronized (mReadBufferLock) {
// mReadBuffer is only used for maximum read size.
readAmt = Math.min(dest.length, mReadBuffer.length);
}
final UsbRequest request = new UsbRequest(); final UsbRequest request = new UsbRequest();
request.initialize(mConnection, endpoint); request.initialize(mConnection, endpoint);
@ -245,27 +242,32 @@ public class FtdiSerialDriver extends UsbSerialDriver {
throw new IOException("Null response"); throw new IOException("Null response");
} }
final int nread = buf.position() - MODEM_STATUS_HEADER_LENGTH; final int payloadBytesRead = buf.position() - MODEM_STATUS_HEADER_LENGTH;
if (nread > 0) { if (payloadBytesRead > 0) {
Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length))); Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
return nread; return payloadBytesRead;
} else { } else {
return 0; return 0;
} }
} else { } else {
final int transferred = mConnection.bulkTransfer(endpoint, mReadBuffer, readAmt, final int totalBytesRead;
timeoutMillis);
if (transferred < MODEM_STATUS_HEADER_LENGTH) { synchronized (mReadBufferLock) {
final int readAmt = Math.min(dest.length, mReadBuffer.length);
totalBytesRead = mConnection.bulkTransfer(endpoint, mReadBuffer,
readAmt, timeoutMillis);
}
if (totalBytesRead < MODEM_STATUS_HEADER_LENGTH) {
throw new IOException("Expected at least " + MODEM_STATUS_HEADER_LENGTH + " bytes"); throw new IOException("Expected at least " + MODEM_STATUS_HEADER_LENGTH + " bytes");
} }
final int nread = transferred - MODEM_STATUS_HEADER_LENGTH; final int payloadBytesRead = totalBytesRead - MODEM_STATUS_HEADER_LENGTH;
if (nread > 0) { if (payloadBytesRead > 0) {
System.arraycopy(mReadBuffer, MODEM_STATUS_HEADER_LENGTH, dest, 0, nread); System.arraycopy(mReadBuffer, MODEM_STATUS_HEADER_LENGTH, dest, 0, payloadBytesRead);
} }
return nread; return payloadBytesRead;
} }
} }
@Override @Override
@ -274,25 +276,32 @@ public class FtdiSerialDriver extends UsbSerialDriver {
int offset = 0; int offset = 0;
while (offset < src.length) { while (offset < src.length) {
final byte[] writeBuffer;
final int writeLength; final int writeLength;
final int amtWritten;
// bulkTransfer does not support offsets; make a copy if necessary. synchronized (mWriteBufferLock) {
writeLength = Math.min(src.length - offset, WRITE_CHUNKSIZE); final byte[] writeBuffer;
if (offset == 0) {
writeBuffer = src; writeLength = Math.min(src.length - offset, mWriteBuffer.length);
} else { if (offset == 0) {
writeBuffer = Arrays.copyOfRange(src, offset, offset + writeLength); writeBuffer = src;
} else {
// bulkTransfer does not support offsets, make a copy.
System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
writeBuffer = mWriteBuffer;
}
amtWritten = mConnection.bulkTransfer(endpoint, writeBuffer, writeLength,
timeoutMillis);
} }
final int amt = mConnection.bulkTransfer(endpoint, writeBuffer, writeLength, if (amtWritten <= 0) {
timeoutMillis);
if (amt <= 0) {
throw new IOException("Error writing " + writeLength throw new IOException("Error writing " + writeLength
+ " bytes at offset " + offset + " length=" + src.length); + " bytes at offset " + offset + " length=" + src.length);
} }
Log.d(TAG, "Wrote amt=" + amt + " attempted=" + writeBuffer.length);
offset += amt; Log.d(TAG, "Wrote amtWritten=" + amtWritten + " attempted=" + writeLength);
offset += amtWritten;
} }
return offset; return offset;
} }

View File

@ -32,12 +32,27 @@ import android.hardware.usb.UsbDeviceConnection;
*/ */
public abstract class UsbSerialDriver { public abstract class UsbSerialDriver {
public static final int DEFAULT_READ_BUFFER_SIZE = 16 * 1024;
public static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024;
protected final UsbDevice mDevice; protected final UsbDevice mDevice;
protected final UsbDeviceConnection mConnection; protected final UsbDeviceConnection mConnection;
protected final Object mReadBufferLock = new Object();
protected final Object mWriteBufferLock = new Object();
/** Internal read buffer. Guarded by {@link #mReadBufferLock}. */
protected byte[] mReadBuffer;
/** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */
protected byte[] mWriteBuffer;
public UsbSerialDriver(UsbDevice device, UsbDeviceConnection connection) { public UsbSerialDriver(UsbDevice device, UsbDeviceConnection connection) {
mDevice = device; mDevice = device;
mConnection = connection; mConnection = connection;
mReadBuffer = new byte[DEFAULT_READ_BUFFER_SIZE];
mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE];
} }
/** /**
@ -93,4 +108,34 @@ public abstract class UsbSerialDriver {
return mDevice; return mDevice;
} }
/**
* Sets the size of the internal buffer used to exchange data with the USB
* stack for read operations. Most users should not need to change this.
*
* @param bufferSize the size in bytes
*/
public final void setReadBufferSize(int bufferSize) {
synchronized (mReadBufferLock) {
if (bufferSize == mReadBuffer.length) {
return;
}
mReadBuffer = new byte[bufferSize];
}
}
/**
* Sets the size of the internal buffer used to exchange data with the USB
* stack for write operations. Most users should not need to change this.
*
* @param bufferSize the size in bytes
*/
public final void setWriteBufferSize(int bufferSize) {
synchronized (mWriteBufferLock) {
if (bufferSize == mWriteBuffer.length) {
return;
}
mWriteBuffer = new byte[bufferSize];
}
}
} }