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