diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java index b837683..e328a5e 100644 --- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java +++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java @@ -1,7 +1,6 @@ package com.hoho.android.usbserial.driver; import java.io.IOException; -import java.util.Arrays; import java.util.LinkedHashMap; import java.util.Map; @@ -21,8 +20,6 @@ public class CdcAcmSerialDriver extends UsbSerialDriver { private final String TAG = CdcAcmSerialDriver.class.getSimpleName(); - private final byte[] mReadBuffer = new byte[4096]; - private UsbInterface mControlInterface; private UsbInterface mDataInterface; @@ -96,47 +93,55 @@ public class CdcAcmSerialDriver extends UsbSerialDriver { @Override public int read(byte[] dest, int timeoutMillis) throws IOException { - int readAmt = Math.min(dest.length, mReadBuffer.length); - readAmt = Math.min(readAmt, mReadEndpoint.getMaxPacketSize()); - final int transferred = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt, - timeoutMillis); - - if (transferred < 0) { - // This sucks: we get -1 on timeout, not 0 as preferred. - // We *should* use UsbRequest, except it has a bug/api oversight - // where there is no way to determine the number of bytes read - // in response :\ -- http://b.android.com/28023 - return 0; + final int numBytesRead; + synchronized (mReadBufferLock) { + int readAmt = Math.min(dest.length, mReadBuffer.length); + readAmt = Math.min(readAmt, mReadEndpoint.getMaxPacketSize()); + numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt, + timeoutMillis); + if (numBytesRead < 0) { + // This sucks: we get -1 on timeout, not 0 as preferred. + // We *should* use UsbRequest, except it has a bug/api oversight + // where there is no way to determine the number of bytes read + // in response :\ -- http://b.android.com/28023 + return 0; + } + System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead); } - System.arraycopy(mReadBuffer, 0, dest, 0, transferred); - return transferred; + return numBytesRead; } @Override public int write(byte[] src, int timeoutMillis) throws IOException { + // TODO(mikey): Nearly identical to FtdiSerial write. Refactor. int offset = 0; - final int chunksize = mWriteEndpoint.getMaxPacketSize(); while (offset < src.length) { - final byte[] writeBuffer; final int writeLength; + final int amtWritten; - // bulkTransfer does not support offsets; make a copy if necessary. - writeLength = Math.min(src.length - offset, chunksize); - if (offset == 0) { - writeBuffer = src; - } else { - writeBuffer = Arrays.copyOfRange(src, offset, offset + writeLength); + synchronized (mWriteBufferLock) { + final byte[] writeBuffer; + + writeLength = Math.min(src.length - offset, mWriteBuffer.length); + if (offset == 0) { + 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); } - - final int amt = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength, - timeoutMillis); - if (amt <= 0) { + if (amtWritten <= 0) { throw new IOException("Error writing " + writeLength + " 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; } diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java index a739fa1..80a1557 100644 --- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java +++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/FtdiSerialDriver.java @@ -22,7 +22,6 @@ package com.hoho.android.usbserial.driver; import java.io.IOException; import java.nio.ByteBuffer; -import java.util.Arrays; import java.util.LinkedHashMap; 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 *
- * This driver is based on libftdi, and is + * This driver is based on + * libftdi, and is * copyright and subject to the following terms: * *
@@ -142,11 +141,6 @@ public class FtdiSerialDriver extends UsbSerialDriver {
public static final int FTDI_DEVICE_IN_REQTYPE =
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.
*/
@@ -156,8 +150,6 @@ public class FtdiSerialDriver extends UsbSerialDriver {
private DeviceType mType;
- private final byte[] mReadBuffer = new byte[4096];
-
/**
* FTDI chip types.
*/
@@ -228,10 +220,15 @@ public class FtdiSerialDriver extends UsbSerialDriver {
@Override
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);
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();
request.initialize(mConnection, endpoint);
@@ -245,27 +242,32 @@ public class FtdiSerialDriver extends UsbSerialDriver {
throw new IOException("Null response");
}
- final int nread = buf.position() - MODEM_STATUS_HEADER_LENGTH;
- if (nread > 0) {
+ final int payloadBytesRead = buf.position() - MODEM_STATUS_HEADER_LENGTH;
+ if (payloadBytesRead > 0) {
Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length)));
- return nread;
+ return payloadBytesRead;
} else {
return 0;
}
} else {
- final int transferred = mConnection.bulkTransfer(endpoint, mReadBuffer, readAmt,
- timeoutMillis);
- if (transferred < MODEM_STATUS_HEADER_LENGTH) {
+ final int totalBytesRead;
+
+ 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");
}
- final int nread = transferred - MODEM_STATUS_HEADER_LENGTH;
- if (nread > 0) {
- System.arraycopy(mReadBuffer, MODEM_STATUS_HEADER_LENGTH, dest, 0, nread);
+ final int payloadBytesRead = totalBytesRead - MODEM_STATUS_HEADER_LENGTH;
+ if (payloadBytesRead > 0) {
+ System.arraycopy(mReadBuffer, MODEM_STATUS_HEADER_LENGTH, dest, 0, payloadBytesRead);
}
- return nread;
+ return payloadBytesRead;
}
-
}
@Override
@@ -274,25 +276,32 @@ public class FtdiSerialDriver extends UsbSerialDriver {
int offset = 0;
while (offset < src.length) {
- final byte[] writeBuffer;
final int writeLength;
+ final int amtWritten;
- // bulkTransfer does not support offsets; make a copy if necessary.
- writeLength = Math.min(src.length - offset, WRITE_CHUNKSIZE);
- if (offset == 0) {
- writeBuffer = src;
- } else {
- writeBuffer = Arrays.copyOfRange(src, offset, offset + writeLength);
+ synchronized (mWriteBufferLock) {
+ final byte[] writeBuffer;
+
+ writeLength = Math.min(src.length - offset, mWriteBuffer.length);
+ if (offset == 0) {
+ 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,
- timeoutMillis);
- if (amt <= 0) {
+ if (amtWritten <= 0) {
throw new IOException("Error writing " + writeLength
+ " 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;
}
diff --git a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialDriver.java b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialDriver.java
index 6ef3ed6..e7f8d01 100644
--- a/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialDriver.java
+++ b/UsbSerialLibrary/src/com/hoho/android/usbserial/driver/UsbSerialDriver.java
@@ -32,12 +32,27 @@ import android.hardware.usb.UsbDeviceConnection;
*/
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 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) {
mDevice = device;
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;
}
+ /**
+ * 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];
+ }
+ }
+
}