From 573c7e41ca687a26293fd111b18df7cf40dd3cd1 Mon Sep 17 00:00:00 2001 From: Self Not Found Date: Thu, 9 Nov 2023 04:12:30 +0800 Subject: [PATCH] Add read() and write() with length argument (#544) To reduce array copy --- .../usbserial/driver/CommonUsbSerialPort.java | 35 ++++++++++++------- .../usbserial/driver/FtdiSerialDriver.java | 21 ++++++++--- .../usbserial/driver/UsbSerialPort.java | 23 ++++++++++++ 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CommonUsbSerialPort.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CommonUsbSerialPort.java index a601509..8cb460e 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CommonUsbSerialPort.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CommonUsbSerialPort.java @@ -169,16 +169,23 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort { @Override public int read(final byte[] dest, final int timeout) throws IOException { - return read(dest, timeout, true); + if(dest.length <= 0) { + throw new IllegalArgumentException("Read buffer too small"); + } + return read(dest, dest.length, timeout); } - protected int read(final byte[] dest, final int timeout, boolean testConnection) throws IOException { + @Override + public int read(final byte[] dest, final int length, final int timeout) throws IOException {return read(dest, length, timeout, true);} + + protected int read(final byte[] dest, int length, final int timeout, boolean testConnection) throws IOException { if(mConnection == null || mUsbRequest == null) { throw new IOException("Connection closed"); } - if(dest.length <= 0) { - throw new IllegalArgumentException("Read buffer to small"); + if(length <= 0) { + throw new IllegalArgumentException("Read length too small"); } + length = Math.min(length, dest.length); final int nread; if (timeout != 0) { // bulkTransfer will cause data loss with short timeout + high baud rates + continuous transfer @@ -190,7 +197,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort { // /system/lib64/libandroid_runtime.so (android_hardware_UsbDeviceConnection_request_wait(_JNIEnv*, _jobject*, long)+84) // data loss / crashes were observed with timeout up to 200 msec long endTime = testConnection ? MonotonicClock.millis() + timeout : 0; - int readMax = Math.min(dest.length, MAX_READ_SIZE); + int readMax = Math.min(length, MAX_READ_SIZE); nread = mConnection.bulkTransfer(mReadEndpoint, dest, readMax, timeout); // Android error propagation is improvable: // nread == -1 can be: timeout, connection lost, buffer to small, ??? @@ -198,8 +205,8 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort { testConnection(); } else { - final ByteBuffer buf = ByteBuffer.wrap(dest); - if (!mUsbRequest.queue(buf, dest.length)) { + final ByteBuffer buf = ByteBuffer.wrap(dest, 0, length); + if (!mUsbRequest.queue(buf, length)) { throw new IOException("Queueing USB request failed"); } final UsbRequest response = mConnection.requestWait(); @@ -217,14 +224,18 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort { } @Override - public void write(final byte[] src, final int timeout) throws IOException { + public void write(byte[] src, int timeout) throws IOException {write(src, src.length, timeout);} + + @Override + public void write(final byte[] src, int length, final int timeout) throws IOException { int offset = 0; final long endTime = (timeout == 0) ? 0 : (MonotonicClock.millis() + timeout); + length = Math.min(length, src.length); if(mConnection == null) { throw new IOException("Connection closed"); } - while (offset < src.length) { + while (offset < length) { int requestTimeout; final int requestLength; final int actualLength; @@ -235,7 +246,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort { if (mWriteBuffer == null) { mWriteBuffer = new byte[mWriteEndpoint.getMaxPacketSize()]; } - requestLength = Math.min(src.length - offset, mWriteBuffer.length); + requestLength = Math.min(length - offset, mWriteBuffer.length); if (offset == 0) { writeBuffer = src; } else { @@ -257,7 +268,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort { } } if (DEBUG) { - Log.d(TAG, "Wrote " + actualLength + "/" + requestLength + " offset " + offset + "/" + src.length + " timeout " + requestTimeout); + Log.d(TAG, "Wrote " + actualLength + "/" + requestLength + " offset " + offset + "/" + length + " timeout " + requestTimeout); } if (actualLength <= 0) { if (timeout != 0 && MonotonicClock.millis() >= endTime) { @@ -265,7 +276,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort { ex.bytesTransferred = offset; throw ex; } else { - throw new IOException("Error writing " + requestLength + " bytes at offset " + offset + " of total " + src.length); + throw new IOException("Error writing " + requestLength + " bytes at offset " + offset + " of total " + length); } } offset += actualLength; diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/FtdiSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/FtdiSerialDriver.java index 291ceeb..ee5fcdc 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/FtdiSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/FtdiSerialDriver.java @@ -139,24 +139,37 @@ public class FtdiSerialDriver implements UsbSerialDriver { } @Override - public int read(final byte[] dest, final int timeout) throws IOException { + public int read(final byte[] dest, final int timeout) throws IOException + { if(dest.length <= READ_HEADER_LENGTH) { - throw new IllegalArgumentException("Read buffer to small"); + throw new IllegalArgumentException("Read buffer too small"); // could allocate larger buffer, including space for 2 header bytes, but this would // result in buffers not being 64 byte aligned any more, causing data loss at continuous // data transfer at high baud rates when buffers are fully filled. } + return read(dest, dest.length, timeout); + } + + @Override + public int read(final byte[] dest, int length, final int timeout) throws IOException { + if(length <= READ_HEADER_LENGTH) { + throw new IllegalArgumentException("Read length too small"); + // could allocate larger buffer, including space for 2 header bytes, but this would + // result in buffers not being 64 byte aligned any more, causing data loss at continuous + // data transfer at high baud rates when buffers are fully filled. + } + length = Math.min(length, dest.length); int nread; if (timeout != 0) { long endTime = MonotonicClock.millis() + timeout; do { - nread = super.read(dest, Math.max(1, (int)(endTime - MonotonicClock.millis())), false); + nread = super.read(dest, length, Math.max(1, (int)(endTime - MonotonicClock.millis())), false); } while (nread == READ_HEADER_LENGTH && MonotonicClock.millis() < endTime); if(nread <= 0 && MonotonicClock.millis() < endTime) testConnection(); } else { do { - nread = super.read(dest, timeout); + nread = super.read(dest, length, timeout); } while (nread == READ_HEADER_LENGTH); } return readFilter(dest, nread); diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbSerialPort.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbSerialPort.java index 3ed9470..45a6e80 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbSerialPort.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbSerialPort.java @@ -122,6 +122,17 @@ public interface UsbSerialPort extends Closeable { */ int read(final byte[] dest, final int timeout) throws IOException; + /** + * Reads bytes with specified length into the destination buffer. + * + * @param dest the destination byte buffer + * @param length the maximum length of the data to read + * @param timeout the timeout for reading in milliseconds, 0 is infinite + * @return the actual number of bytes read + * @throws IOException if an error occurred during reading + */ + int read(final byte[] dest, int length, final int timeout) throws IOException; + /** * Writes as many bytes as possible from the source buffer. * @@ -133,6 +144,18 @@ public interface UsbSerialPort extends Closeable { */ void write(final byte[] src, final int timeout) throws IOException; + /** + * Writes bytes with specified length from the source buffer. + * + * @param src the source byte buffer + * @param length the length of the data to write + * @param timeout the timeout for writing in milliseconds, 0 is infinite + * @throws SerialTimeoutException if timeout reached before sending all data. + * ex.bytesTransferred may contain bytes transferred + * @throws IOException if an error occurred during writing + */ + void write(final byte[] src, int length, final int timeout) throws IOException; + /** * Sets various serial port parameters. *