diff --git a/.gitignore b/.gitignore
index 0bd3eef1..fbc65d55 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,5 @@ local.properties
*.DS_Store
proguard/
jacoco.exec
+
+.idea
\ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 4ee2d22f..00000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
-caches
-codeStyles
-libraries
-workspace.xml
-androidTestResultsUserPreferences.xml
-appInsightsSettings.xml
-deploymentTargetDropDown.xml
-deploymentTargetSelector.xml
-other.xml
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index b86273d9..00000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index b96734e1..00000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
deleted file mode 100644
index 16660f1d..00000000
--- a/.idea/runConfigurations.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 35eb1ddf..00000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java
index df82d5dc..0a40f71c 100644
--- a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java
+++ b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java
@@ -361,9 +361,9 @@ public void prolificBaudRate() throws Exception {
Assume.assumeTrue("only for Prolific", usb.serialDriver instanceof ProlificSerialDriver);
int[] baudRates = {
- 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400, 19200,
- 28800, 38400, 57600, 115200, 128000, 134400, 161280, 201600, 230400, 268800,
- 403200, 460800, 614400, 806400, 921600, 1228800, 2457600, 3000000, /*6000000*/
+ 75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 14400, 19200,
+ 28800, 38400, 57600, 115200, 128000, 134400, 161280, 201600, 230400, 268800,
+ 403200, 460800, 614400, 806400, 921600, 1228800, 2457600, 3000000, /*6000000*/
};
usb.open();
Assume.assumeFalse("only for non PL2303G*", ProlificSerialPortWrapper.isDeviceTypeHxn(usb.serialPort)); // HXN does not use divisor
@@ -469,7 +469,7 @@ public void Ch34xBaudRate() throws Exception {
usb.open();
int[] baudRates = {
- 115200, 230400, 256000, 307200, 460800, 921600, 1000000, 1228800
+ 115200, 230400, 256000, 307200, 460800, 921600, 1000000, 1228800
};
for (int baudRate : baudRates) {
telnet.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);
@@ -647,8 +647,8 @@ public void dataBits() throws Exception {
data = telnet.read(2);
assertThat("19000/7N1", data, equalTo(new byte[]{(byte) 0x80, (byte) 0xff}));
} catch (UnsupportedOperationException e) {
- if(!usb.isCp21xxRestrictedPort)
- throw e;
+ if(!usb.isCp21xxRestrictedPort)
+ throw e;
}
try {
usb.setParameters(19200, 6, 1, UsbSerialPort.PARITY_NONE);
@@ -873,9 +873,9 @@ public void writeSizes() throws Exception {
((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(-1);
((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(-1);
assertEquals(usb.serialPort.getWriteEndpoint().getMaxPacketSize(),
- CommonUsbSerialPortWrapper.getWriteBuffer(usb.serialPort).length);
+ CommonUsbSerialPortWrapper.getWriteBuffer(usb.serialPort).length);
assertEquals(usb.serialPort.getWriteEndpoint().getMaxPacketSize(),
- usb.serialPort.getReadEndpoint().getMaxPacketSize());
+ usb.serialPort.getReadEndpoint().getMaxPacketSize());
int baudRate = 300;
if(usb.serialDriver instanceof Cp21xxSerialDriver && usb.serialPort.getPortNumber() > 0)
@@ -945,7 +945,7 @@ public void writeTimeout() throws Exception {
} catch(SerialTimeoutException ex) {
assertTrue(ex.getMessage(), ex.getMessage().endsWith("rc=-1")); // timeout in bulkTransfer
for(byte[] data = telnet.read(-1, readWait); data.length != 0;
- data = telnet.read(-1, readWait)) {
+ data = telnet.read(-1, readWait)) {
tbuf.testRead(data);
}
assertEquals(0, ex.bytesTransferred);
@@ -960,7 +960,7 @@ public void writeTimeout() throws Exception {
} catch(SerialTimeoutException ex) {
assertTrue(ex.getMessage(), ex.getMessage().endsWith("rc=-1")); // timeout in bulkTransfer
for(byte[] data = telnet.read(-1, readWait); data.length != 0;
- data = telnet.read(-1, readWait)) {
+ data = telnet.read(-1, readWait)) {
tbuf.testRead(data);
}
assertEquals(usb.writeBufferSize + usb.writePacketSize, ex.bytesTransferred);
@@ -1117,7 +1117,7 @@ else if (usb.serialDriver instanceof ProlificSerialDriver)
fail("IllegalArgumentException expected");
} catch (IllegalArgumentException ignored) {}
}
-
+
telnet.write("2aaa".getBytes());
data = usb.read(4, 8);
assertThat(data, equalTo("2aaa".getBytes()));
@@ -1209,13 +1209,13 @@ public void readSpeed() throws Exception {
// Android is not a real time OS, so there is no guarantee that the USB thread is scheduled, or it might be blocked by Java garbage collection.
// Using SERIAL_INPUT_OUTPUT_MANAGER_THREAD_PRIORITY=THREAD_PRIORITY_URGENT_AUDIO sometimes reduced errors by factor 10, sometimes not at all!
//
- int diffLen = readSpeedInt(5, -1, 0);
+ int diffLen = readSpeedInt(5, -1);
if(usb.serialDriver instanceof Ch34xSerialDriver && diffLen == -1)
- diffLen = 0; // todo: investigate last packet loss
+ diffLen = 0; // todo: investigate last packet loss
assertEquals(0, diffLen);
}
- private int readSpeedInt(int writeSeconds, int readBufferSize, int readTimeout) throws Exception {
+ private int readSpeedInt(int writeSeconds, int readBufferSize) throws Exception {
int baudrate = 115200;
if(usb.serialDriver instanceof Ch34xSerialDriver)
baudrate = 38400;
@@ -1224,7 +1224,6 @@ private int readSpeedInt(int writeSeconds, int readBufferSize, int readTimeout)
writeAhead = 50;
usb.open(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_IOMANAGER_START));
- usb.ioManager.setReadTimeout(readTimeout);
if(readBufferSize > 0)
usb.ioManager.setReadBufferSize(readBufferSize);
usb.ioManager.start();
@@ -1379,7 +1378,7 @@ public void purgeHwBuffers() throws Exception {
assertThat(usb.read(1), equalTo("y".getBytes())); // cp2105/0
} else {
assertThat(usb.read(2), anyOf(equalTo("xy".getBytes()), // cp2102
- equalTo("y".getBytes()))); // cp2102
+ equalTo("y".getBytes()))); // cp2102
}
} else {
assertThat(usb.read(1), equalTo("y".getBytes()));
@@ -1401,9 +1400,6 @@ public void IoManager() throws Exception {
usb.ioManager = new SerialInputOutputManager(usb.serialPort, usb);
assertEquals(usb, usb.ioManager.getListener());
- assertEquals(0, usb.ioManager.getReadTimeout());
- usb.ioManager.setReadTimeout(10);
- assertEquals(10, usb.ioManager.getReadTimeout());
assertEquals(0, usb.ioManager.getWriteTimeout());
usb.ioManager.setWriteTimeout(11);
assertEquals(11, usb.ioManager.getWriteTimeout());
@@ -1417,7 +1413,6 @@ public void IoManager() throws Exception {
usb.ioManager.setReadBufferSize(usb.ioManager.getReadBufferSize());
usb.ioManager.setWriteBufferSize(usb.ioManager.getWriteBufferSize());
- usb.ioManager.setReadTimeout(usb.ioManager.getReadTimeout());
usb.ioManager.setWriteTimeout(usb.ioManager.getWriteTimeout());
usb.close();
@@ -1426,6 +1421,8 @@ public void IoManager() throws Exception {
telnet.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
usb.ioManager.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
assertEquals(SerialInputOutputManager.State.STOPPED, usb.ioManager.getState());
+ usb.ioManager.setReadBufferSize(22);
+ assertEquals(22, usb.ioManager.getReadBufferSize());
usb.ioManager.start();
usb.waitForIoManagerStarted();
assertEquals(SerialInputOutputManager.State.RUNNING, usb.ioManager.getState());
@@ -1439,35 +1436,17 @@ public void IoManager() throws Exception {
usb.ioManager.setThreadPriority(Process.THREAD_PRIORITY_LOWEST);
fail("setThreadPriority IllegalStateException expected");
} catch (IllegalStateException ignored) {}
- try {
- usb.ioManager.setReadTimeout(20);
- fail("setReadTimeout IllegalStateException expected");
- } catch (IllegalStateException ignored) {}
- assertEquals(0, usb.ioManager.getReadTimeout());
usb.ioManager.setWriteTimeout(21);
assertEquals(21, usb.ioManager.getWriteTimeout());
- usb.ioManager.setReadBufferSize(22);
- assertEquals(22, usb.ioManager.getReadBufferSize());
usb.ioManager.setWriteBufferSize(23);
assertEquals(23, usb.ioManager.getWriteBufferSize());
- // readbuffer resize
- telnet.write(new byte[1]);
- usb.ioManager.setReadBufferSize(64);
- Log.d(TAG, "setReadBufferSize(64)");
- telnet.write(new byte[1]); // still uses old buffer as infinite waiting step() holds reference to buffer
- telnet.write(new byte[1]); // now uses 8 byte buffer
- usb.read(3);
-
// small writebuffer
try {
usb.ioManager.writeAsync(new byte[8192]);
fail("expected BufferOverflowException");
} catch (BufferOverflowException ignored) {}
- // small readbuffer
- usb.ioManager.setReadBufferSize(8);
- Log.d(TAG, "setReadBufferSize(8)");
telnet.write("b".getBytes());
assertThat(usb.read(1), equalTo("b".getBytes()));
// now new buffer is used
@@ -1569,13 +1548,13 @@ public void readTimeout() throws Exception {
int diffLen;
usb.close();
// no issue with high transfer rate and long read timeout
- diffLen = readSpeedInt(5, -1, longTimeout);
+ diffLen = readSpeedInt(5, -1);
if(usb.serialDriver instanceof Ch34xSerialDriver && diffLen == -1)
diffLen = 0; // todo: investigate last packet loss
assertEquals(0, diffLen);
usb.close();
// date loss with high transfer rate and short read timeout !!!
- diffLen = readSpeedInt(5, -1, shortTimeout);
+ diffLen = readSpeedInt(5, -1);
assertNotEquals("sporadic issue!", 0, diffLen);
@@ -1615,7 +1594,7 @@ public void wrongDriver() throws Exception {
}
wrongSerialPort.close();
if(!(usb.serialDriver instanceof Ch34xSerialDriver |
- usb.serialDriver instanceof ProlificSerialDriver))
+ usb.serialDriver instanceof ProlificSerialDriver))
fail("error expected");
} catch (IOException ignored) {
}
@@ -1787,9 +1766,9 @@ public void controlLines() throws Exception {
// control lines reset on initial open
data = "none".getBytes();
assertEquals(usb.inputLinesConnected && !usb.inputLinesOnlyRtsCts
- ? EnumSet.of(ControlLine.RI)
- : EnumSet.noneOf(ControlLine.class),
- usb.serialPort.getControlLines());
+ ? EnumSet.of(ControlLine.RI)
+ : EnumSet.noneOf(ControlLine.class),
+ usb.serialPort.getControlLines());
assertThat(usb.getControlLine(usb.serialPort::getRTS), equalTo(Boolean.FALSE));
assertThat(usb.getControlLine(usb.serialPort::getCTS), equalTo(inputLineFalse));
assertThat(usb.getControlLine(usb.serialPort::getDTR), equalTo(Boolean.FALSE));
@@ -1810,9 +1789,9 @@ public void controlLines() throws Exception {
usb.serialPort.setRTS(true);
Thread.sleep(sleep);
assertEquals(usb.inputLinesConnected
- ? EnumSet.of(ControlLine.RTS, ControlLine.CTS)
- : EnumSet.of(ControlLine.RTS),
- usb.serialPort.getControlLines());
+ ? EnumSet.of(ControlLine.RTS, ControlLine.CTS)
+ : EnumSet.of(ControlLine.RTS),
+ usb.serialPort.getControlLines());
assertThat(usb.getControlLine(usb.serialPort::getRTS), equalTo(Boolean.TRUE));
assertThat(usb.getControlLine(usb.serialPort::getCTS), equalTo(inputLineTrue));
assertThat(usb.getControlLine(usb.serialPort::getDTR), equalTo(Boolean.FALSE));
@@ -1830,9 +1809,9 @@ public void controlLines() throws Exception {
assertEquals(usb.inputLinesOnlyRtsCts
? EnumSet.of(ControlLine.RTS, ControlLine.DTR, ControlLine.CTS)
: usb.inputLinesConnected
- ? EnumSet.of(ControlLine.RTS, ControlLine.DTR, ControlLine.CD)
- : EnumSet.of(ControlLine.RTS, ControlLine.DTR),
- usb.serialPort.getControlLines());
+ ? EnumSet.of(ControlLine.RTS, ControlLine.DTR, ControlLine.CD)
+ : EnumSet.of(ControlLine.RTS, ControlLine.DTR),
+ usb.serialPort.getControlLines());
assertThat(usb.getControlLine(usb.serialPort::getRTS), equalTo(Boolean.TRUE));
assertThat(usb.getControlLine(usb.serialPort::getCTS), equalTo(usb.inputLinesOnlyRtsCts ? Boolean.TRUE : inputLineFalse));
assertThat(usb.getControlLine(usb.serialPort::getDTR), equalTo(Boolean.TRUE));
@@ -1848,9 +1827,9 @@ public void controlLines() throws Exception {
usb.serialPort.setRTS(false);
Thread.sleep(sleep);
assertEquals(usb.inputLinesConnected && !usb.inputLinesOnlyRtsCts
- ? EnumSet.of(ControlLine.DTR, ControlLine.DSR)
- : EnumSet.of(ControlLine.DTR),
- usb.serialPort.getControlLines());
+ ? EnumSet.of(ControlLine.DTR, ControlLine.DSR)
+ : EnumSet.of(ControlLine.DTR),
+ usb.serialPort.getControlLines());
assertThat(usb.getControlLine(usb.serialPort::getRTS), equalTo(Boolean.FALSE));
assertThat(usb.getControlLine(usb.serialPort::getCTS), equalTo(inputLineFalse));
assertThat(usb.getControlLine(usb.serialPort::getDTR), equalTo(Boolean.TRUE));
@@ -1973,7 +1952,7 @@ public void flowControlXonXoff() throws Exception {
Assume.assumeTrue("flow control not supported", false);
}
if (usb.serialPort.getSupportedFlowControl().contains(FlowControl.XON_XOFF_INLINE) &&
- usb.serialPort.getSupportedFlowControl().contains(FlowControl.XON_XOFF)) {
+ usb.serialPort.getSupportedFlowControl().contains(FlowControl.XON_XOFF)) {
fail("only one of both XON_XOFF variants allowed");
}
if (usb.serialPort.getSupportedFlowControl().contains(FlowControl.XON_XOFF_INLINE)) {
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 546f0ab9..23d14fa3 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
@@ -163,7 +163,8 @@ public void close() throws IOException {
/**
* use simple USB request supported by all devices to test if connection is still valid
*/
- protected void testConnection(boolean full) throws IOException {
+ @Override
+ public void testConnection(boolean full) throws IOException {
testConnection(full, "USB get_status request failed");
}
@@ -354,4 +355,9 @@ public void setFlowControl(FlowControl flowcontrol) throws IOException {
@Override
public void setBreak(boolean value) throws IOException { throw new UnsupportedOperationException(); }
+ @Override
+ public UsbDeviceConnection getConnection() {
+ return mConnection;
+ }
+
}
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 ebf96df5..93232e79 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
@@ -321,4 +321,13 @@ enum FlowControl { NONE, RTS_CTS, DTR_DSR, XON_XOFF, XON_XOFF_INLINE }
*/
boolean isOpen();
+ /**
+ * Returns the underlying {@link UsbDeviceConnection}.
+ */
+ UsbDeviceConnection getConnection();
+
+ /**
+ * use simple USB request supported by all devices to test if connection is still valid
+ */
+ void testConnection(boolean full) throws IOException;
}
diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/util/SerialInputOutputManager.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/util/SerialInputOutputManager.java
index c22a2b8c..40ca47a8 100644
--- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/util/SerialInputOutputManager.java
+++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/util/SerialInputOutputManager.java
@@ -6,8 +6,10 @@
package com.hoho.android.usbserial.util;
+import android.hardware.usb.UsbRequest;
import android.os.Process;
import android.util.Log;
+import androidx.annotation.VisibleForTesting;
import com.hoho.android.usbserial.driver.UsbSerialPort;
@@ -35,13 +37,12 @@ public enum State {
private static final String TAG = SerialInputOutputManager.class.getSimpleName();
private static final int BUFSIZ = 4096;
- private int mReadTimeout = 0;
private int mWriteTimeout = 0;
- private final Object mReadBufferLock = new Object();
private final Object mWriteBufferLock = new Object();
- private ByteBuffer mReadBuffer; // default size = getReadEndpoint().getMaxPacketSize()
+ private int mReadBufferSize; // default size = getReadEndpoint().getMaxPacketSize()
+ private int mReadBufferCount = 4;
private ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);
private int mThreadPriority = Process.THREAD_PRIORITY_URGENT_AUDIO;
@@ -64,13 +65,13 @@ public interface Listener {
public SerialInputOutputManager(UsbSerialPort serialPort) {
mSerialPort = serialPort;
- mReadBuffer = ByteBuffer.allocate(serialPort.getReadEndpoint().getMaxPacketSize());
+ mReadBufferSize = serialPort.getReadEndpoint().getMaxPacketSize();
}
public SerialInputOutputManager(UsbSerialPort serialPort, Listener listener) {
mSerialPort = serialPort;
mListener = listener;
- mReadBuffer = ByteBuffer.allocate(serialPort.getReadEndpoint().getMaxPacketSize());
+ mReadBufferSize = serialPort.getReadEndpoint().getMaxPacketSize();
}
public synchronized void setListener(Listener listener) {
@@ -94,17 +95,20 @@ public void setThreadPriority(int threadPriority) {
}
/**
- * read/write timeout
+ * read buffer count
*/
- public void setReadTimeout(int timeout) {
- // when set if already running, read already blocks and the new value will not become effective now
- if(mReadTimeout == 0 && timeout != 0 && mState.get() != State.STOPPED)
- throw new IllegalStateException("readTimeout only configurable before SerialInputOutputManager is started");
- mReadTimeout = timeout;
+ public int getReadBufferCount() {
+ return mReadBufferCount;
}
- public int getReadTimeout() {
- return mReadTimeout;
+ /**
+ * read buffer count
+ */
+ public void setReadBufferCount(int mReadBuffeCount) {
+ if (!mState.compareAndSet(State.STOPPED, State.STOPPED)) {
+ throw new IllegalStateException("ReadBufferCount only configurable before SerialInputOutputManager is started");
+ }
+ this.mReadBufferCount = mReadBuffeCount;
}
public void setWriteTimeout(int timeout) {
@@ -119,17 +123,19 @@ public int getWriteTimeout() {
* read/write buffer size
*/
public void setReadBufferSize(int bufferSize) {
- if (getReadBufferSize() == bufferSize)
- return;
- synchronized (mReadBufferLock) {
- mReadBuffer = ByteBuffer.allocate(bufferSize);
+ if (getReadBufferSize() != bufferSize) {
+ if (!mState.compareAndSet(State.STOPPED, State.STOPPED)) {
+ throw new IllegalStateException("ReadBuffeCount only configurable before SerialInputOutputManager is started");
+ }
+ mReadBufferSize = bufferSize;
}
}
public int getReadBufferSize() {
- return mReadBuffer.capacity();
+ return mReadBufferSize;
}
+
public void setWriteBufferSize(int bufferSize) {
if(getWriteBufferSize() == bufferSize)
return;
@@ -227,28 +233,39 @@ private void setThreadPriority() {
}
}
+ @VisibleForTesting
+ protected UsbRequest getUsbRequest() {
+ return new UsbRequest();
+ }
+
/**
* Continuously services the read buffers until {@link #stop()} is called, or until a driver exception is
* raised.
*/
- void runRead() {
+ public void runRead() {
Log.i(TAG, "runRead running ...");
try {
setThreadPriority();
mStartuplatch.countDown();
+ // Initialize buffers and requests
+ for (int i = 0; i < mReadBufferCount; i++) {
+ ByteBuffer buffer = ByteBuffer.allocate(mReadBufferSize);
+ UsbRequest request = getUsbRequest();
+ request.setClientData(buffer);
+ request.initialize(mSerialPort.getConnection(), mSerialPort.getReadEndpoint());
+ request.queue(buffer, buffer.capacity());
+ }
do {
stepRead();
} while (isStillRunning());
Log.i(TAG, "runRead: Stopping mState=" + getState());
} catch (Throwable e) {
if (Thread.currentThread().isInterrupted()) {
- Log.w(TAG, "runRead: interrupted");
- } else if(mSerialPort.isOpen()) {
- Log.w(TAG, "runRead ending due to exception: " + e.getMessage(), e);
+ Log.w(TAG, "Thread interrupted, stopping runRead.");
} else {
- Log.i(TAG, "runRead: Socket closed");
+ Log.w(TAG, "runRead ending due to exception: " + e.getMessage(), e);
+ notifyErrorListener(e);
}
- notifyErrorListener(e);
} finally {
if (!mState.compareAndSet(State.RUNNING, State.STOPPING)) {
if (mState.compareAndSet(State.STOPPING, State.STOPPED)) {
@@ -262,7 +279,7 @@ void runRead() {
* Continuously services the write buffers until {@link #stop()} is called, or until a driver exception is
* raised.
*/
- void runWrite() {
+ public void runWrite() {
Log.i(TAG, "runWrite running ...");
try {
setThreadPriority();
@@ -290,22 +307,29 @@ void runWrite() {
}
private void stepRead() throws IOException {
- // Handle incoming data.
- byte[] buffer;
- synchronized (mReadBufferLock) {
- buffer = mReadBuffer.array();
- }
- int len = mSerialPort.read(buffer, mReadTimeout);
- if (len > 0) {
- if (DEBUG) {
- Log.d(TAG, "Read data len=" + len);
- }
+ // Wait for the request to complete
+ final UsbRequest completedRequest = mSerialPort.getConnection().requestWait();
+ if (completedRequest != null) {
+ final ByteBuffer completedBuffer = (ByteBuffer) completedRequest.getClientData();
+ completedBuffer.flip(); // Prepare for reading
+ final byte[] data = new byte[completedBuffer.remaining()];
+ completedBuffer.get(data);
final Listener listener = getListener();
- if (listener != null) {
- final byte[] data = new byte[len];
- System.arraycopy(buffer, 0, data, 0, len);
- listener.onNewData(data);
+ if ((listener != null) && (data.length > 0)) {
+ listener.onNewData(data); // Handle data
+ }
+ if (data.length == 0) {
+ mSerialPort.testConnection(true);
}
+ completedBuffer.clear(); // Prepare for reuse
+ // Requeue the buffer and handle potential failures
+ if (!completedRequest.queue(completedBuffer, completedBuffer.capacity())) {
+ Log.e(TAG, "Failed to requeue the buffer");
+ throw new IOException("Failed to requeue the buffer");
+ }
+ } else {
+ Log.e(TAG, "Error waiting for request");
+ throw new IOException("Error waiting for request");
}
}
diff --git a/usbSerialForAndroid/src/test/java/com/hoho/android/usbserial/util/SerialInputOutputManagerTest.java b/usbSerialForAndroid/src/test/java/com/hoho/android/usbserial/util/SerialInputOutputManagerTest.java
index 63d9f209..d2e23c42 100644
--- a/usbSerialForAndroid/src/test/java/com/hoho/android/usbserial/util/SerialInputOutputManagerTest.java
+++ b/usbSerialForAndroid/src/test/java/com/hoho/android/usbserial/util/SerialInputOutputManagerTest.java
@@ -4,15 +4,39 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import java.nio.ByteBuffer;
+
+import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbRequest;
import android.os.Process;
import com.hoho.android.usbserial.driver.CommonUsbSerialPort;
+import com.hoho.android.usbserial.driver.UsbSerialPort;
import org.junit.Test;
public class SerialInputOutputManagerTest {
+ private static class TestSerialInputOutputManager extends SerialInputOutputManager {
+
+ private final UsbRequest mRequest;
+
+ public TestSerialInputOutputManager(UsbSerialPort serialPort, UsbRequest mRequest) {
+ super(serialPort);
+ this.mRequest = mRequest;
+ }
+
+ public TestSerialInputOutputManager(UsbSerialPort serialPort, Listener listener, UsbRequest mRequest) {
+ super(serialPort, listener);
+ this.mRequest = mRequest;
+ }
+
+ @Override
+ protected UsbRequest getUsbRequest() {
+ return mRequest;
+ }
+ }
// catch all Throwables in onNewData() and onRunError()
@Test
@@ -29,13 +53,16 @@ class ErrorListener implements SerialInputOutputManager.Listener {
@Override public void onRunError(Exception e) { this.e = e; throw new UnknownError("error2");}
}
+ UsbRequest request = mock(UsbRequest.class);
UsbEndpoint readEndpoint = mock(UsbEndpoint.class);
+ UsbDeviceConnection connection = mock(UsbDeviceConnection.class);
when(readEndpoint.getMaxPacketSize()).thenReturn(16);
CommonUsbSerialPort port = mock(CommonUsbSerialPort.class);
when(port.getReadEndpoint()).thenReturn(readEndpoint);
- when(port.read(new byte[16], 0)).thenReturn(1);
- when(port.isOpen()).thenReturn(true);
- SerialInputOutputManager manager = new SerialInputOutputManager(port);
+ when(port.getConnection()).thenReturn(connection);
+ when(connection.requestWait()).thenReturn(request);
+ when(request.getClientData()).thenReturn(ByteBuffer.wrap(new byte[16]).put((byte) 0x00));
+ SerialInputOutputManager manager = new TestSerialInputOutputManager(port, request);
manager.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
ExceptionListener exceptionListener = new ExceptionListener();