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];
+        }
+    }
+
 }