From 9ea936b14a971edc5702f1f97fa61b0948351e01 Mon Sep 17 00:00:00 2001 From: kai-morich Date: Sun, 27 Oct 2019 21:32:38 +0100 Subject: [PATCH 1/8] improve close handling Use releaseInterface to interrupt read() and terminate SerialInputOutputManager. Previously some drivers used usbRequest.cancel() but this does not interrupt read() on older Android. Added connection check to read(). Before Android 8.0 request.initialize() did not check usbConnection, which can lead to native crash if NULL --- .../hoho/android/usbserial/DeviceTest.java | 97 +++++++++++-------- .../usbserial/driver/CdcAcmSerialDriver.java | 19 ++-- .../usbserial/driver/Ch34xSerialDriver.java | 14 +-- .../usbserial/driver/Cp21xxSerialDriver.java | 14 +-- .../usbserial/driver/FtdiSerialDriver.java | 3 + .../driver/ProlificSerialDriver.java | 3 + 6 files changed, 80 insertions(+), 70 deletions(-) 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 4d92811..049f409 100644 --- a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java +++ b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java @@ -42,7 +42,11 @@ import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; import org.junit.runner.RunWith; import java.io.IOException; @@ -103,6 +107,13 @@ public class DeviceTest implements SerialInputOutputManager.Listener { private int telnetWriteDelay = 0; private boolean isCp21xxRestrictedPort = false; // second port of Cp2105 has limited dataBits, stopBits, parity + @Rule + public TestRule watcher = new TestWatcher() { + protected void starting(Description description) { + Log.i(TAG, "===== starting test: " + description.getMethodName()+ " ====="); + } + }; + @BeforeClass public static void setUpFixture() throws Exception { rfc2217_server_host = InstrumentationRegistry.getArguments().getString("rfc2217_server_host"); @@ -164,32 +175,35 @@ public class DeviceTest implements SerialInputOutputManager.Listener { isCp21xxRestrictedPort = usbSerialDriver instanceof Cp21xxSerialDriver && usbSerialDriver.getPorts().size()==2 && test_device_port == 1; if (!usbManager.hasPermission(usbSerialPort.getDriver().getDevice())) { - final Boolean[] granted = {Boolean.FALSE}; + Log.d(TAG,"USB permission ..."); + final Boolean[] granted = {null}; BroadcastReceiver usbReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - granted[0] = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false); - synchronized (granted) { - granted.notify(); - } + granted[0] = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false); } }; PendingIntent permissionIntent = PendingIntent.getBroadcast(context, 0, new Intent("com.android.example.USB_PERMISSION"), 0); IntentFilter filter = new IntentFilter("com.android.example.USB_PERMISSION"); context.registerReceiver(usbReceiver, filter); usbManager.requestPermission(usbSerialDriver.getDevice(), permissionIntent); - synchronized (granted) { - granted.wait(5000); + for(int i=0; i<5000; i++) { + if(granted[0] != null) break; + Thread.sleep(1); } - assertTrue("USB permission dialog not confirmed", granted[0]); + Log.d(TAG,"USB permission "+granted[0]); + assertTrue("USB permission dialog not confirmed", granted[0]==null?false:granted[0]); + telnetRead(-1); // doesn't look related here, but very often after usb permission dialog the first test failed with telnet garbage } - usbOpen(true); } @After public void tearDown() throws IOException { try { - usbRead(0); + if(usbIoManager != null) + usbRead(0); + else + usbSerialPort.purgeHwBuffers(true, true); } catch (Exception ignored) {} try { telnetRead(0); @@ -257,16 +271,14 @@ public class DeviceTest implements SerialInputOutputManager.Listener { } try { usbSerialPort.close(); - } catch (IOException ignored) { + } catch (Exception ignored) { } usbSerialPort = null; } - if(usbDeviceConnection != null) - usbDeviceConnection.close(); - usbDeviceConnection = null; + usbDeviceConnection = null; // closed in usbSerialPort.close() if(usbIoManager != null) { - for(int i=0; i<2000; i++) { - if(SerialInputOutputManager.State.STOPPED == usbIoManager.getState()) break; + for (int i = 0; i < 2000; i++) { + if (SerialInputOutputManager.State.STOPPED == usbIoManager.getState()) break; try { Thread.sleep(1); } catch (InterruptedException e) { @@ -473,7 +485,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { @Test public void openClose() throws Exception { - byte[] data; + usbOpen(true); telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); doReadWrite(""); @@ -485,11 +497,12 @@ public class DeviceTest implements SerialInputOutputManager.Listener { } doReadWrite(""); - usbSerialPort.close(); + usbClose(); try { usbSerialPort.close(); fail("already closed expected"); } catch (IOException ignored) { + } catch (NullPointerException ignored) { } try { usbWrite(new byte[]{0x00}); @@ -510,25 +523,6 @@ public class DeviceTest implements SerialInputOutputManager.Listener { } catch (NullPointerException ignored) { } - // partial re-open not supported - try { - usbSerialPort.open(usbDeviceConnection); - //usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); - doReadWrite(""); - fail("re-open not supported"); - } catch (IOException ignored) { - } - try { - usbSerialPort.close(); - } catch (IOException ignored) { - } - - if (usbSerialDriver instanceof Cp21xxSerialDriver) { // why needed? - usbIoManager.stop(); - usbIoManager = null; - } - // full re-open supported - usbClose(); usbOpen(true); telnetParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE); usbParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE); @@ -537,6 +531,8 @@ public class DeviceTest implements SerialInputOutputManager.Listener { @Test public void baudRate() throws Exception { + usbOpen(true); + if (false) { // default baud rate // CP2102: only works if first connection after attaching device // PL2303, FTDI: it's not 9600 @@ -670,6 +666,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { public void dataBits() throws Exception { byte[] data; + usbOpen(true); for(int i: new int[] {0, 4, 9}) { try { usbParameters(19200, i, 1, UsbSerialPort.PARITY_NONE); @@ -753,6 +750,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { byte[] _7s1 = {(byte)0x00, (byte)0x01, (byte)0x7e, (byte)0x7f}; byte[] data; + usbOpen(true); for(int i: new int[] {-1, 5}) { try { usbParameters(19200, 8, 1, i); @@ -849,6 +847,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { public void stopBits() throws Exception { byte[] data; + usbOpen(true); for (int i : new int[]{0, 4}) { try { usbParameters(19200, 8, i, UsbSerialPort.PARITY_NONE); @@ -929,6 +928,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { public void readBufferOverflow() throws Exception { if(usbSerialDriver instanceof CdcAcmSerialDriver) telnetWriteDelay = 10; // arduino_leonardo_bridge.ino sends each byte in own USB packet, which is horribly slow + usbOpen(true); usbParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); @@ -990,6 +990,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { // Using SERIAL_INPUT_OUTPUT_MANAGER_THREAD_PRIORITY=THREAD_PRIORITY_URGENT_AUDIO sometimes reduced errors by factor 10, sometimes not at all! // int baudrate = 115200; + usbOpen(true); usbParameters(baudrate, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(baudrate, 8, 1, UsbSerialPort.PARITY_NONE); @@ -1043,6 +1044,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { // all other devices can get near physical limit: // longlines=true:, speed is near physical limit at 11.5k // longlines=false: speed is 3-4k for all devices, as more USB packets are required + usbOpen(true); usbParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); boolean longlines = !(usbSerialDriver instanceof CdcAcmSerialDriver); @@ -1092,6 +1094,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { @Test public void purgeHwBuffers() throws Exception { // 2400 is slowest baud rate for isCp21xxRestrictedPort + usbOpen(true); usbParameters(2400, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(2400, 8, 1, UsbSerialPort.PARITY_NONE); byte[] buf = new byte[64]; @@ -1122,6 +1125,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { public void writeAsync() throws Exception { if (usbSerialDriver instanceof FtdiSerialDriver) return; // periodically sends status messages, so does not block here + usbOpen(true); usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); @@ -1156,6 +1160,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { public void readSync() throws Exception { if (usbSerialDriver instanceof FtdiSerialDriver) return; // periodically sends status messages, so does not block here + final Boolean[] closed = {Boolean.FALSE}; Runnable closeThread = new Runnable() { @Override @@ -1166,10 +1171,10 @@ public class DeviceTest implements SerialInputOutputManager.Listener { e.printStackTrace(); } usbClose(); + closed[0] = true; } }; - usbClose(); usbOpen(false); usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); @@ -1182,19 +1187,35 @@ public class DeviceTest implements SerialInputOutputManager.Listener { assertEquals(1, len); time = System.currentTimeMillis(); + closed[0] = false; Executors.newSingleThreadExecutor().submit(closeThread); len = usbSerialPort.read(buf, 0); // blocking until close() assertEquals(0, len); assertTrue(System.currentTimeMillis()-time >= 100); + + // read() terminates in the middle of close(). An immediate open() can fail with 'already connected' + // because close() is not finished yet. Wait here until fully closed. In a real-world application + // where it takes some time until the user clicks on reconnect, this very likely is not an issue. + for(int i=0; i<=100; i++) { + if(closed[0]) break; + assertTrue("not closed in time", i<100); + Thread.sleep(1); + } usbOpen(false); usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); time = System.currentTimeMillis(); + closed[0] = false; Executors.newSingleThreadExecutor().submit(closeThread); len = usbSerialPort.read(buf, 10); // timeout not used any more -> blocking until close() assertEquals(0, len); assertTrue(System.currentTimeMillis()-time >= 100); + for(int i=0; i<=100; i++) { + if(closed[0]) break; + assertTrue("not closed in time", i<100); + Thread.sleep(1); + } } } diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java index 1e02232..33eb17e 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java @@ -50,7 +50,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { private final UsbDevice mDevice; private final UsbSerialPort mPort; - private UsbRequest mUsbRequest; public CdcAcmSerialDriver(UsbDevice device) { mDevice = device; @@ -254,28 +253,27 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { if (mConnection == null) { throw new IOException("Already closed"); } - synchronized (this) { - if (mUsbRequest != null) - mUsbRequest.cancel(); + try { + mConnection.releaseInterface(mControlInterface); + mConnection.releaseInterface(mDataInterface); + mConnection.close(); + } finally { + mConnection = null; } - mConnection.close(); - mConnection = null; } @Override public int read(byte[] dest, int timeoutMillis) throws IOException { final UsbRequest request = new UsbRequest(); try { + if(mConnection == null) + throw new IOException("Connection closed"); request.initialize(mConnection, mReadEndpoint); final ByteBuffer buf = ByteBuffer.wrap(dest); if (!request.queue(buf, dest.length)) { throw new IOException("Error queueing request."); } - mUsbRequest = request; final UsbRequest response = mConnection.requestWait(); - synchronized (this) { - mUsbRequest = null; - } if (response == null) { throw new IOException("Null response"); } @@ -288,7 +286,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { return 0; } } finally { - mUsbRequest = null; request.close(); } } diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java index b35cbef..31c36ed 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java @@ -85,7 +85,6 @@ public class Ch34xSerialDriver implements UsbSerialDriver { private UsbEndpoint mReadEndpoint; private UsbEndpoint mWriteEndpoint; - private UsbRequest mUsbRequest; public Ch340SerialPort(UsbDevice device, int portNumber) { super(device, portNumber); @@ -144,11 +143,9 @@ public class Ch34xSerialDriver implements UsbSerialDriver { if (mConnection == null) { throw new IOException("Already closed"); } - synchronized (this) { - if (mUsbRequest != null) - mUsbRequest.cancel(); - } try { + for (int i = 0; i < mDevice.getInterfaceCount(); i++) + mConnection.releaseInterface(mDevice.getInterface(i)); mConnection.close(); } finally { mConnection = null; @@ -160,16 +157,14 @@ public class Ch34xSerialDriver implements UsbSerialDriver { public int read(byte[] dest, int timeoutMillis) throws IOException { final UsbRequest request = new UsbRequest(); try { + if(mConnection == null) + throw new IOException("Connection closed"); request.initialize(mConnection, mReadEndpoint); final ByteBuffer buf = ByteBuffer.wrap(dest); if (!request.queue(buf, dest.length)) { throw new IOException("Error queueing request."); } - mUsbRequest = request; final UsbRequest response = mConnection.requestWait(); - synchronized (this) { - mUsbRequest = null; - } if (response == null) { throw new IOException("Null response"); } @@ -182,7 +177,6 @@ public class Ch34xSerialDriver implements UsbSerialDriver { return 0; } } finally { - mUsbRequest = null; request.close(); } } diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java index 8bd90f0..67fa528 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java @@ -108,7 +108,6 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { private UsbEndpoint mReadEndpoint; private UsbEndpoint mWriteEndpoint; - private UsbRequest mUsbRequest; // second port of Cp2105 has limited baudRate, dataBits, stopBits, parity // unsupported baudrate returns error at controlTransfer(), other parameters are silently ignored @@ -177,16 +176,12 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { if (mConnection == null) { throw new IOException("Already closed"); } - synchronized (this) { - if(mUsbRequest != null) { - mUsbRequest.cancel(); - } - } try { setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE); } catch (Exception ignored) {} try { + mConnection.releaseInterface(mDevice.getInterface(mPortNumber)); mConnection.close(); } finally { mConnection = null; @@ -197,16 +192,14 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { public int read(byte[] dest, int timeoutMillis) throws IOException { final UsbRequest request = new UsbRequest(); try { + if(mConnection == null) + throw new IOException("Connection closed"); request.initialize(mConnection, mReadEndpoint); final ByteBuffer buf = ByteBuffer.wrap(dest); if (!request.queue(buf, dest.length)) { throw new IOException("Error queueing request."); } - mUsbRequest = request; final UsbRequest response = mConnection.requestWait(); - synchronized (this) { - mUsbRequest = null; - } if (response == null) { throw new IOException("Null response"); } @@ -219,7 +212,6 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { return 0; } } finally { - mUsbRequest = null; request.close(); } } 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 60d0632..585b84b 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 @@ -268,6 +268,7 @@ public class FtdiSerialDriver implements UsbSerialDriver { throw new IOException("Already closed"); } try { + mConnection.releaseInterface(mDevice.getInterface(mPortNumber)); mConnection.close(); } finally { mConnection = null; @@ -280,6 +281,8 @@ public class FtdiSerialDriver implements UsbSerialDriver { final UsbRequest request = new UsbRequest(); final ByteBuffer buf = ByteBuffer.wrap(dest); try { + if(mConnection == null) + throw new IOException("Connection closed"); request.initialize(mConnection, endpoint); if (!request.queue(buf, dest.length)) { throw new IOException("Error queueing request."); diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java index 24ae76e..9830b56 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java @@ -362,6 +362,7 @@ public class ProlificSerialDriver implements UsbSerialDriver { } finally { try { mConnection.releaseInterface(mDevice.getInterface(0)); + mConnection.close(); } finally { mConnection = null; } @@ -372,6 +373,8 @@ public class ProlificSerialDriver implements UsbSerialDriver { public int read(byte[] dest, int timeoutMillis) throws IOException { final UsbRequest request = new UsbRequest(); try { + if(mConnection == null) + throw new IOException("Connection closed"); request.initialize(mConnection, mReadEndpoint); final ByteBuffer buf = ByteBuffer.wrap(dest); if (!request.queue(buf, dest.length)) { From 6869eff88aebd838c6ecd2483ee7a805c3d0cd71 Mon Sep 17 00:00:00 2001 From: kai-morich Date: Sat, 2 Nov 2019 11:24:58 +0100 Subject: [PATCH 2/8] revert previous usbRequest.cancel() removal Combine usbRequest.cancel() and releaseInterface to interrupt read() and terminate SerialInputOutputManager. UsbRequest.cancel() immediately interrupts read() on newer Android versions. With releaseInterface() only, some hickup are observed on fast reconnect. Keep releaseInterface() as only this interrupts read() on older Androids. --- .../usbserial/driver/CdcAcmSerialDriver.java | 12 ++++++++++++ .../usbserial/driver/Ch34xSerialDriver.java | 12 ++++++++++++ .../usbserial/driver/Cp21xxSerialDriver.java | 16 ++++++++++++++-- .../usbserial/driver/FtdiSerialDriver.java | 2 ++ .../usbserial/driver/ProlificSerialDriver.java | 2 ++ 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java index 33eb17e..773f355 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java @@ -50,6 +50,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { private final UsbDevice mDevice; private final UsbSerialPort mPort; + private UsbRequest mUsbRequest; public CdcAcmSerialDriver(UsbDevice device) { mDevice = device; @@ -253,9 +254,15 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { if (mConnection == null) { throw new IOException("Already closed"); } + synchronized (this) { + if (mUsbRequest != null) + mUsbRequest.cancel(); + } try { mConnection.releaseInterface(mControlInterface); mConnection.releaseInterface(mDataInterface); + } catch(Exception ignored) {} + try { mConnection.close(); } finally { mConnection = null; @@ -273,7 +280,11 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { if (!request.queue(buf, dest.length)) { throw new IOException("Error queueing request."); } + mUsbRequest = request; final UsbRequest response = mConnection.requestWait(); + synchronized (this) { + mUsbRequest = null; + } if (response == null) { throw new IOException("Null response"); } @@ -286,6 +297,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { return 0; } } finally { + mUsbRequest = null; request.close(); } } diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java index 31c36ed..7b36171 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java @@ -85,6 +85,7 @@ public class Ch34xSerialDriver implements UsbSerialDriver { private UsbEndpoint mReadEndpoint; private UsbEndpoint mWriteEndpoint; + private UsbRequest mUsbRequest; public Ch340SerialPort(UsbDevice device, int portNumber) { super(device, portNumber); @@ -143,9 +144,15 @@ public class Ch34xSerialDriver implements UsbSerialDriver { if (mConnection == null) { throw new IOException("Already closed"); } + synchronized (this) { + if (mUsbRequest != null) + mUsbRequest.cancel(); + } try { for (int i = 0; i < mDevice.getInterfaceCount(); i++) mConnection.releaseInterface(mDevice.getInterface(i)); + } catch(Exception ignored) {} + try { mConnection.close(); } finally { mConnection = null; @@ -164,7 +171,11 @@ public class Ch34xSerialDriver implements UsbSerialDriver { if (!request.queue(buf, dest.length)) { throw new IOException("Error queueing request."); } + mUsbRequest = request; final UsbRequest response = mConnection.requestWait(); + synchronized (this) { + mUsbRequest = null; + } if (response == null) { throw new IOException("Null response"); } @@ -177,6 +188,7 @@ public class Ch34xSerialDriver implements UsbSerialDriver { return 0; } } finally { + mUsbRequest = null; request.close(); } } diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java index 67fa528..11d9823 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java @@ -108,6 +108,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { private UsbEndpoint mReadEndpoint; private UsbEndpoint mWriteEndpoint; + private UsbRequest mUsbRequest; // second port of Cp2105 has limited baudRate, dataBits, stopBits, parity // unsupported baudrate returns error at controlTransfer(), other parameters are silently ignored @@ -176,12 +177,18 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { if (mConnection == null) { throw new IOException("Already closed"); } + synchronized (this) { + if(mUsbRequest != null) { + mUsbRequest.cancel(); + } + } try { setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE); - } catch (Exception ignored) - {} + } catch (Exception ignored) {} try { mConnection.releaseInterface(mDevice.getInterface(mPortNumber)); + } catch(Exception ignored) {} + try { mConnection.close(); } finally { mConnection = null; @@ -199,7 +206,11 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { if (!request.queue(buf, dest.length)) { throw new IOException("Error queueing request."); } + mUsbRequest = request; final UsbRequest response = mConnection.requestWait(); + synchronized (this) { + mUsbRequest = null; + } if (response == null) { throw new IOException("Null response"); } @@ -212,6 +223,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { return 0; } } finally { + mUsbRequest = null; request.close(); } } 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 585b84b..8dbdfd4 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 @@ -269,6 +269,8 @@ public class FtdiSerialDriver implements UsbSerialDriver { } try { mConnection.releaseInterface(mDevice.getInterface(mPortNumber)); + } catch(Exception ignored) {} + try { mConnection.close(); } finally { mConnection = null; diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java index 9830b56..d4928fc 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java @@ -362,6 +362,8 @@ public class ProlificSerialDriver implements UsbSerialDriver { } finally { try { mConnection.releaseInterface(mDevice.getInterface(0)); + } catch(Exception ignored) {} + try { mConnection.close(); } finally { mConnection = null; From 18b5b6e6485d1602ade8f0eb673bcedab2ef681f Mon Sep 17 00:00:00 2001 From: kai-morich Date: Sat, 2 Nov 2019 13:03:11 +0100 Subject: [PATCH 3/8] unify open() error handling, more tests, minor cleanup --- .../hoho/android/usbserial/DeviceTest.java | 137 ++- .../usbserial/driver/CdcAcmSerialDriver.java | 909 +++++++++--------- .../usbserial/driver/Ch34xSerialDriver.java | 14 +- .../usbserial/driver/Cp21xxSerialDriver.java | 22 +- .../usbserial/driver/FtdiSerialDriver.java | 9 +- .../android/usbserial/driver/ProbeTable.java | 12 +- .../driver/ProlificSerialDriver.java | 11 +- .../usbserial/driver/UsbSerialProber.java | 11 +- 8 files changed, 618 insertions(+), 507 deletions(-) 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 049f409..377b6dc 100644 --- a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java +++ b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java @@ -229,7 +229,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { private byte[] telnetRead(int expectedLength) throws Exception { long end = System.currentTimeMillis() + TELNET_READ_WAIT; - ByteBuffer buf = ByteBuffer.allocate(4096); + ByteBuffer buf = ByteBuffer.allocate(8192); while(System.currentTimeMillis() < end) { if(telnetReadStream.available() > 0) { buf.put((byte) telnetReadStream.read()); @@ -498,23 +498,21 @@ public class DeviceTest implements SerialInputOutputManager.Listener { doReadWrite(""); usbClose(); + usbSerialPort = usbSerialDriver.getPorts().get(test_device_port); try { usbSerialPort.close(); fail("already closed expected"); } catch (IOException ignored) { - } catch (NullPointerException ignored) { } try { usbWrite(new byte[]{0x00}); fail("write error expected"); } catch (IOException ignored) { - } catch (NullPointerException ignored) { } try { usbRead(1); - //fail("read error expected"); + fail("read error expected"); } catch (IOException ignored) { - } catch (NullPointerException ignored) { } try { usbParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE); @@ -522,11 +520,22 @@ public class DeviceTest implements SerialInputOutputManager.Listener { } catch (IOException ignored) { } catch (NullPointerException ignored) { } + usbSerialPort = null; usbOpen(true); telnetParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE); usbParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE); doReadWrite(""); + + // close before iomanager + assertEquals(SerialInputOutputManager.State.RUNNING, usbIoManager.getState()); + usbSerialPort.close(); + for (int i = 0; i < 1000; i++) { + if (usbIoManager.getState() == SerialInputOutputManager.State.STOPPED) + break; + Thread.sleep(1); + } + assertEquals(SerialInputOutputManager.State.STOPPED, usbIoManager.getState()); } @Test @@ -684,21 +693,21 @@ public class DeviceTest implements SerialInputOutputManager.Listener { usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(19200, 7, 1, UsbSerialPort.PARITY_NONE); telnetWrite(new byte[] {0x00}); - Thread.sleep(1); // one bit is 0.05 milliseconds long, wait >> stop bit + Thread.sleep(10); // one bit is 0.05 milliseconds long, wait >> stop bit telnetWrite(new byte[] {(byte)0xff}); data = usbRead(2); assertThat("19200/7N1", data, equalTo(new byte[] {(byte)0x80, (byte)0xff})); telnetParameters(19200, 6, 1, UsbSerialPort.PARITY_NONE); telnetWrite(new byte[] {0x00}); - Thread.sleep(1); + Thread.sleep(10); telnetWrite(new byte[] {(byte)0xff}); data = usbRead(2); assertThat("19000/6N1", data, equalTo(new byte[] {(byte)0xc0, (byte)0xff})); telnetParameters(19200, 5, 1, UsbSerialPort.PARITY_NONE); telnetWrite(new byte[] {0x00}); - Thread.sleep(1); + Thread.sleep(10); telnetWrite(new byte[] {(byte)0xff}); data = usbRead(2); assertThat("19000/5N1", data, equalTo(new byte[] {(byte)0xe0, (byte)0xff})); @@ -708,7 +717,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); usbParameters(19200, 7, 1, UsbSerialPort.PARITY_NONE); usbWrite(new byte[]{0x00}); - Thread.sleep(1); + Thread.sleep(10); usbWrite(new byte[]{(byte) 0xff}); data = telnetRead(2); assertThat("19000/7N1", data, equalTo(new byte[]{(byte) 0x80, (byte) 0xff})); @@ -719,7 +728,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { try { usbParameters(19200, 6, 1, UsbSerialPort.PARITY_NONE); usbWrite(new byte[]{0x00}); - Thread.sleep(1); + Thread.sleep(10); usbWrite(new byte[]{(byte) 0xff}); data = telnetRead(2); assertThat("19000/6N1", data, equalTo(new byte[]{(byte) 0xc0, (byte) 0xff})); @@ -730,7 +739,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { try { usbParameters(19200, 5, 1, UsbSerialPort.PARITY_NONE); usbWrite(new byte[] {0x00}); - Thread.sleep(1); + Thread.sleep(5); usbWrite(new byte[] {(byte)0xff}); data = telnetRead(2); assertThat("19000/5N1", data, equalTo(new byte[] {(byte)0xe0, (byte)0xff})); @@ -1217,5 +1226,109 @@ public class DeviceTest implements SerialInputOutputManager.Listener { assertTrue("not closed in time", i<100); Thread.sleep(1); } - } + } + + @Test + public void wrongDriver() throws Exception { + + UsbDeviceConnection wrongDeviceConnection; + UsbSerialDriver wrongSerialDriver; + UsbSerialPort wrongSerialPort; + + if(!(usbSerialDriver instanceof CdcAcmSerialDriver)) { + wrongDeviceConnection = usbManager.openDevice(usbSerialDriver.getDevice()); + wrongSerialDriver = new CdcAcmSerialDriver(usbSerialDriver.getDevice()); + wrongSerialPort = wrongSerialDriver.getPorts().get(0); + try { + wrongSerialPort.open(wrongDeviceConnection); + wrongSerialPort.setParameters(115200, UsbSerialPort.DATABITS_8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE); // ch340 fails here + wrongSerialPort.write(new byte[]{1}, 1000); // pl2302 does not fail, but sends with wrong baud rate + if(!(usbSerialDriver instanceof ProlificSerialDriver)) + fail("error expected"); + } catch (IOException ignored) { + } + try { + if(usbSerialDriver instanceof ProlificSerialDriver) { + assertNotEquals(new byte[]{1}, telnetRead()); + } + wrongSerialPort.close(); + if(!(usbSerialDriver instanceof Ch34xSerialDriver | + usbSerialDriver instanceof ProlificSerialDriver)) + fail("error expected"); + } catch (IOException ignored) { + } + } + if(!(usbSerialDriver instanceof Ch34xSerialDriver)) { + wrongDeviceConnection = usbManager.openDevice(usbSerialDriver.getDevice()); + wrongSerialDriver = new Ch34xSerialDriver(usbSerialDriver.getDevice()); + wrongSerialPort = wrongSerialDriver.getPorts().get(0); + try { + wrongSerialPort.open(wrongDeviceConnection); + fail("error expected"); + } catch (IOException ignored) { + } + try { + wrongSerialPort.close(); + fail("error expected"); + } catch (IOException ignored) { + } + } + // FTDI only recovers from Cp21xx control commands with power toggle, so skip this combination! + if(!(usbSerialDriver instanceof Cp21xxSerialDriver | usbSerialDriver instanceof FtdiSerialDriver)) { + wrongDeviceConnection = usbManager.openDevice(usbSerialDriver.getDevice()); + wrongSerialDriver = new Cp21xxSerialDriver(usbSerialDriver.getDevice()); + wrongSerialPort = wrongSerialDriver.getPorts().get(0); + try { + wrongSerialPort.open(wrongDeviceConnection); + //if(usbSerialDriver instanceof FtdiSerialDriver) + // wrongSerialPort.setParameters(115200, UsbSerialPort.DATABITS_8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE); // ch340 fails here + fail("error expected"); + } catch (IOException ignored) { + } + try { + wrongSerialPort.close(); + //if(!(usbSerialDriver instanceof FtdiSerialDriver)) + // fail("error expected"); + } catch (IOException ignored) { + } + } + if(!(usbSerialDriver instanceof FtdiSerialDriver)) { + wrongDeviceConnection = usbManager.openDevice(usbSerialDriver.getDevice()); + wrongSerialDriver = new FtdiSerialDriver(usbSerialDriver.getDevice()); + wrongSerialPort = wrongSerialDriver.getPorts().get(0); + try { + wrongSerialPort.open(wrongDeviceConnection); + if(usbSerialDriver instanceof Cp21xxSerialDriver) + wrongSerialPort.setParameters(115200, UsbSerialPort.DATABITS_8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE); // ch340 fails here + fail("error expected"); + } catch (IOException ignored) { + } + try { + wrongSerialPort.close(); + if(!(usbSerialDriver instanceof Cp21xxSerialDriver)) + fail("error expected"); + } catch (IOException ignored) { + } + } + if(!(usbSerialDriver instanceof ProlificSerialDriver)) { + wrongDeviceConnection = usbManager.openDevice(usbSerialDriver.getDevice()); + wrongSerialDriver = new ProlificSerialDriver(usbSerialDriver.getDevice()); + wrongSerialPort = wrongSerialDriver.getPorts().get(0); + try { + wrongSerialPort.open(wrongDeviceConnection); + fail("error expected"); + } catch (IOException ignored) { + } + try { + wrongSerialPort.close(); + fail("error expected"); + } catch (IOException ignored) { + } + } + // test that device recovers from wrong commands + usbOpen(true); + telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); + usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); + doReadWrite(""); + } } diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java index 773f355..6d17453 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java @@ -1,454 +1,455 @@ -/* Copyright 2011-2013 Google Inc. - * Copyright 2013 mike wakerly - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - * - * Project home page: https://github.com/mik3y/usb-serial-for-android - */ - -package com.hoho.android.usbserial.driver; - -import android.hardware.usb.UsbConstants; -import android.hardware.usb.UsbDevice; -import android.hardware.usb.UsbDeviceConnection; -import android.hardware.usb.UsbEndpoint; -import android.hardware.usb.UsbInterface; -import android.hardware.usb.UsbRequest; -import android.util.Log; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -/** - * USB CDC/ACM serial driver implementation. - * - * @author mike wakerly (opensource@hoho.com) - * @see Universal - * Serial Bus Class Definitions for Communication Devices, v1.1 - */ -public class CdcAcmSerialDriver implements UsbSerialDriver { - - private final String TAG = CdcAcmSerialDriver.class.getSimpleName(); - - private final UsbDevice mDevice; - private final UsbSerialPort mPort; - private UsbRequest mUsbRequest; - - public CdcAcmSerialDriver(UsbDevice device) { - mDevice = device; - mPort = new CdcAcmSerialPort(device, 0); - } - - @Override - public UsbDevice getDevice() { - return mDevice; - } - - @Override - public List getPorts() { - return Collections.singletonList(mPort); - } - - class CdcAcmSerialPort extends CommonUsbSerialPort { - - private UsbInterface mControlInterface; - private UsbInterface mDataInterface; - - private UsbEndpoint mControlEndpoint; - private UsbEndpoint mReadEndpoint; - private UsbEndpoint mWriteEndpoint; - - private int mControlIndex; - - private boolean mRts = false; - private boolean mDtr = false; - - private static final int USB_RECIP_INTERFACE = 0x01; - private static final int USB_RT_ACM = UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE; - - private static final int SET_LINE_CODING = 0x20; // USB CDC 1.1 section 6.2 - private static final int GET_LINE_CODING = 0x21; - private static final int SET_CONTROL_LINE_STATE = 0x22; - private static final int SEND_BREAK = 0x23; - - public CdcAcmSerialPort(UsbDevice device, int portNumber) { - super(device, portNumber); - } - - @Override - public UsbSerialDriver getDriver() { - return CdcAcmSerialDriver.this; - } - - @Override - public void open(UsbDeviceConnection connection) throws IOException { - if (mConnection != null) { - throw new IOException("Already open"); - } - - mConnection = connection; - boolean opened = false; - try { - - if (1 == mDevice.getInterfaceCount()) { - Log.d(TAG,"device might be castrated ACM device, trying single interface logic"); - openSingleInterface(); - } else { - Log.d(TAG,"trying default interface logic"); - openInterface(); - } - - opened = true; - } finally { - if (!opened) { - mConnection = null; - // just to be on the save side - mControlEndpoint = null; - mReadEndpoint = null; - mWriteEndpoint = null; - } - } - } - - private void openSingleInterface() throws IOException { - // the following code is inspired by the cdc-acm driver - // in the linux kernel - - mControlIndex = 0; - mControlInterface = mDevice.getInterface(0); - Log.d(TAG, "Control iface=" + mControlInterface); - - mDataInterface = mDevice.getInterface(0); - Log.d(TAG, "data iface=" + mDataInterface); - - if (!mConnection.claimInterface(mControlInterface, true)) { - throw new IOException("Could not claim shared control/data interface."); - } - - int endCount = mControlInterface.getEndpointCount(); - - if (endCount < 3) { - Log.d(TAG,"not enough endpoints - need 3. count=" + mControlInterface.getEndpointCount()); - throw new IOException("Insufficient number of endpoints(" + mControlInterface.getEndpointCount() + ")"); - } - - // Analyse endpoints for their properties - mControlEndpoint = null; - mReadEndpoint = null; - mWriteEndpoint = null; - for (int i = 0; i < endCount; ++i) { - UsbEndpoint ep = mControlInterface.getEndpoint(i); - if ((ep.getDirection() == UsbConstants.USB_DIR_IN) && - (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_INT)) { - Log.d(TAG,"Found controlling endpoint"); - mControlEndpoint = ep; - } else if ((ep.getDirection() == UsbConstants.USB_DIR_IN) && - (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)) { - Log.d(TAG,"Found reading endpoint"); - mReadEndpoint = ep; - } else if ((ep.getDirection() == UsbConstants.USB_DIR_OUT) && - (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)) { - Log.d(TAG,"Found writing endpoint"); - mWriteEndpoint = ep; - } - - - if ((mControlEndpoint != null) && - (mReadEndpoint != null) && - (mWriteEndpoint != null)) { - Log.d(TAG,"Found all required endpoints"); - break; - } - } - - if ((mControlEndpoint == null) || - (mReadEndpoint == null) || - (mWriteEndpoint == null)) { - Log.d(TAG,"Could not establish all endpoints"); - throw new IOException("Could not establish all endpoints"); - } - } - - private void openInterface() throws IOException { - Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount()); - - mControlInterface = null; - mDataInterface = null; - for (int i = 0; i < mDevice.getInterfaceCount(); i++) { - UsbInterface usbInterface = mDevice.getInterface(i); - if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_COMM) { - mControlIndex = i; - mControlInterface = usbInterface; - } - if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) { - mDataInterface = usbInterface; - } - } - - if(mControlInterface == null) { - throw new IOException("no control interface."); - } - Log.d(TAG, "Control iface=" + mControlInterface); - - if (!mConnection.claimInterface(mControlInterface, true)) { - throw new IOException("Could not claim control interface."); - } - - mControlEndpoint = mControlInterface.getEndpoint(0); - if (mControlEndpoint.getDirection() != UsbConstants.USB_DIR_IN || mControlEndpoint.getType() != UsbConstants.USB_ENDPOINT_XFER_INT) { - throw new IOException("invalid control endpoint"); - } - - if(mDataInterface == null) { - throw new IOException("no data interface."); - } - Log.d(TAG, "data iface=" + mDataInterface); - - if (!mConnection.claimInterface(mDataInterface, true)) { - throw new IOException("Could not claim data interface."); - } - - mReadEndpoint = null; - mWriteEndpoint = null; - for (int i = 0; i < mDataInterface.getEndpointCount(); i++) { - UsbEndpoint ep = mDataInterface.getEndpoint(i); - if (ep.getDirection() == UsbConstants.USB_DIR_IN && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) - mReadEndpoint = ep; - if (ep.getDirection() == UsbConstants.USB_DIR_OUT && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) - mWriteEndpoint = ep; - } - if (mReadEndpoint == null || mWriteEndpoint == null) { - throw new IOException("Could not get read&write endpoints."); - } - } - - private int sendAcmControlMessage(int request, int value, byte[] buf) throws IOException { - int len = mConnection.controlTransfer( - USB_RT_ACM, request, value, mControlIndex, buf, buf != null ? buf.length : 0, 5000); - if(len < 0) { - throw new IOException("controlTransfer failed."); - } - return len; - } - - @Override - public void close() throws IOException { - if (mConnection == null) { - throw new IOException("Already closed"); - } - synchronized (this) { - if (mUsbRequest != null) - mUsbRequest.cancel(); - } - try { - mConnection.releaseInterface(mControlInterface); - mConnection.releaseInterface(mDataInterface); - } catch(Exception ignored) {} - try { - mConnection.close(); - } finally { - mConnection = null; - } - } - - @Override - public int read(byte[] dest, int timeoutMillis) throws IOException { - final UsbRequest request = new UsbRequest(); - try { - if(mConnection == null) - throw new IOException("Connection closed"); - request.initialize(mConnection, mReadEndpoint); - final ByteBuffer buf = ByteBuffer.wrap(dest); - if (!request.queue(buf, dest.length)) { - throw new IOException("Error queueing request."); - } - mUsbRequest = request; - final UsbRequest response = mConnection.requestWait(); - synchronized (this) { - mUsbRequest = null; - } - if (response == null) { - throw new IOException("Null response"); - } - - final int nread = buf.position(); - if (nread > 0) { - //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length))); - return nread; - } else { - return 0; - } - } finally { - mUsbRequest = null; - request.close(); - } - } - - @Override - public int write(byte[] src, int timeoutMillis) throws IOException { - // TODO(mikey): Nearly identical to FtdiSerial write. Refactor. - int offset = 0; - - while (offset < src.length) { - final int writeLength; - final int amtWritten; - - 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); - } - if (amtWritten <= 0) { - throw new IOException("Error writing " + writeLength - + " bytes at offset " + offset + " length=" + src.length); - } - - Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength); - offset += amtWritten; - } - return offset; - } - - @Override - public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException { - byte stopBitsByte; - switch (stopBits) { - case STOPBITS_1: stopBitsByte = 0; break; - case STOPBITS_1_5: stopBitsByte = 1; break; - case STOPBITS_2: stopBitsByte = 2; break; - default: throw new IllegalArgumentException("Bad value for stopBits: " + stopBits); - } - - byte parityBitesByte; - switch (parity) { - case PARITY_NONE: parityBitesByte = 0; break; - case PARITY_ODD: parityBitesByte = 1; break; - case PARITY_EVEN: parityBitesByte = 2; break; - case PARITY_MARK: parityBitesByte = 3; break; - case PARITY_SPACE: parityBitesByte = 4; break; - default: throw new IllegalArgumentException("Bad value for parity: " + parity); - } - - byte[] msg = { - (byte) ( baudRate & 0xff), - (byte) ((baudRate >> 8 ) & 0xff), - (byte) ((baudRate >> 16) & 0xff), - (byte) ((baudRate >> 24) & 0xff), - stopBitsByte, - parityBitesByte, - (byte) dataBits}; - sendAcmControlMessage(SET_LINE_CODING, 0, msg); - } - - @Override - public boolean getCD() throws IOException { - return false; // TODO - } - - @Override - public boolean getCTS() throws IOException { - return false; // TODO - } - - @Override - public boolean getDSR() throws IOException { - return false; // TODO - } - - @Override - public boolean getDTR() throws IOException { - return mDtr; - } - - @Override - public void setDTR(boolean value) throws IOException { - mDtr = value; - setDtrRts(); - } - - @Override - public boolean getRI() throws IOException { - return false; // TODO - } - - @Override - public boolean getRTS() throws IOException { - return mRts; - } - - @Override - public void setRTS(boolean value) throws IOException { - mRts = value; - setDtrRts(); - } - - private void setDtrRts() throws IOException { - int value = (mRts ? 0x2 : 0) | (mDtr ? 0x1 : 0); - sendAcmControlMessage(SET_CONTROL_LINE_STATE, value, null); - } - - } - - public static Map getSupportedDevices() { - final Map supportedDevices = new LinkedHashMap(); - supportedDevices.put(UsbId.VENDOR_ARDUINO, - new int[] { - UsbId.ARDUINO_UNO, - UsbId.ARDUINO_UNO_R3, - UsbId.ARDUINO_MEGA_2560, - UsbId.ARDUINO_MEGA_2560_R3, - UsbId.ARDUINO_SERIAL_ADAPTER, - UsbId.ARDUINO_SERIAL_ADAPTER_R3, - UsbId.ARDUINO_MEGA_ADK, - UsbId.ARDUINO_MEGA_ADK_R3, - UsbId.ARDUINO_LEONARDO, - UsbId.ARDUINO_MICRO, - }); - supportedDevices.put(UsbId.VENDOR_VAN_OOIJEN_TECH, - new int[] { - UsbId.VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL, - }); - supportedDevices.put(UsbId.VENDOR_ATMEL, - new int[] { - UsbId.ATMEL_LUFA_CDC_DEMO_APP, - }); - supportedDevices.put(UsbId.VENDOR_LEAFLABS, - new int[] { - UsbId.LEAFLABS_MAPLE, - }); - supportedDevices.put(UsbId.VENDOR_ARM, - new int[] { - UsbId.ARM_MBED, - }); - return supportedDevices; - } - -} +/* Copyright 2011-2013 Google Inc. + * Copyright 2013 mike wakerly + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + * USA. + * + * Project home page: https://github.com/mik3y/usb-serial-for-android + */ + +package com.hoho.android.usbserial.driver; + +import android.hardware.usb.UsbConstants; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbDeviceConnection; +import android.hardware.usb.UsbEndpoint; +import android.hardware.usb.UsbInterface; +import android.hardware.usb.UsbRequest; +import android.util.Log; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * USB CDC/ACM serial driver implementation. + * + * @author mike wakerly (opensource@hoho.com) + * @see Universal + * Serial Bus Class Definitions for Communication Devices, v1.1 + */ +public class CdcAcmSerialDriver implements UsbSerialDriver { + + private final String TAG = CdcAcmSerialDriver.class.getSimpleName(); + + private final UsbDevice mDevice; + private final UsbSerialPort mPort; + private UsbRequest mUsbRequest; + + public CdcAcmSerialDriver(UsbDevice device) { + mDevice = device; + mPort = new CdcAcmSerialPort(device, 0); + } + + @Override + public UsbDevice getDevice() { + return mDevice; + } + + @Override + public List getPorts() { + return Collections.singletonList(mPort); + } + + class CdcAcmSerialPort extends CommonUsbSerialPort { + + private UsbInterface mControlInterface; + private UsbInterface mDataInterface; + + private UsbEndpoint mControlEndpoint; + private UsbEndpoint mReadEndpoint; + private UsbEndpoint mWriteEndpoint; + + private int mControlIndex; + + private boolean mRts = false; + private boolean mDtr = false; + + private static final int USB_RECIP_INTERFACE = 0x01; + private static final int USB_RT_ACM = UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE; + + private static final int SET_LINE_CODING = 0x20; // USB CDC 1.1 section 6.2 + private static final int GET_LINE_CODING = 0x21; + private static final int SET_CONTROL_LINE_STATE = 0x22; + private static final int SEND_BREAK = 0x23; + + public CdcAcmSerialPort(UsbDevice device, int portNumber) { + super(device, portNumber); + } + + @Override + public UsbSerialDriver getDriver() { + return CdcAcmSerialDriver.this; + } + + @Override + public void open(UsbDeviceConnection connection) throws IOException { + if (mConnection != null) { + throw new IOException("Already open"); + } + + mConnection = connection; + boolean opened = false; + try { + if (1 == mDevice.getInterfaceCount()) { + Log.d(TAG,"device might be castrated ACM device, trying single interface logic"); + openSingleInterface(); + } else { + Log.d(TAG,"trying default interface logic"); + openInterface(); + } + opened = true; + } finally { + if (!opened) { + close(); + } + } + } + + private void openSingleInterface() throws IOException { + // the following code is inspired by the cdc-acm driver + // in the linux kernel + + mControlIndex = 0; + mControlInterface = mDevice.getInterface(0); + Log.d(TAG, "Control iface=" + mControlInterface); + + mDataInterface = mDevice.getInterface(0); + Log.d(TAG, "data iface=" + mDataInterface); + + if (!mConnection.claimInterface(mControlInterface, true)) { + throw new IOException("Could not claim shared control/data interface."); + } + + int endCount = mControlInterface.getEndpointCount(); + + if (endCount < 3) { + Log.d(TAG,"not enough endpoints - need 3. count=" + mControlInterface.getEndpointCount()); + throw new IOException("Insufficient number of endpoints(" + mControlInterface.getEndpointCount() + ")"); + } + + // Analyse endpoints for their properties + mControlEndpoint = null; + mReadEndpoint = null; + mWriteEndpoint = null; + for (int i = 0; i < endCount; ++i) { + UsbEndpoint ep = mControlInterface.getEndpoint(i); + if ((ep.getDirection() == UsbConstants.USB_DIR_IN) && + (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_INT)) { + Log.d(TAG,"Found controlling endpoint"); + mControlEndpoint = ep; + } else if ((ep.getDirection() == UsbConstants.USB_DIR_IN) && + (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)) { + Log.d(TAG,"Found reading endpoint"); + mReadEndpoint = ep; + } else if ((ep.getDirection() == UsbConstants.USB_DIR_OUT) && + (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)) { + Log.d(TAG,"Found writing endpoint"); + mWriteEndpoint = ep; + } + + + if ((mControlEndpoint != null) && + (mReadEndpoint != null) && + (mWriteEndpoint != null)) { + Log.d(TAG,"Found all required endpoints"); + break; + } + } + + if ((mControlEndpoint == null) || + (mReadEndpoint == null) || + (mWriteEndpoint == null)) { + Log.d(TAG,"Could not establish all endpoints"); + throw new IOException("Could not establish all endpoints"); + } + } + + private void openInterface() throws IOException { + Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount()); + + mControlInterface = null; + mDataInterface = null; + for (int i = 0; i < mDevice.getInterfaceCount(); i++) { + UsbInterface usbInterface = mDevice.getInterface(i); + if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_COMM) { + mControlIndex = i; + mControlInterface = usbInterface; + } + if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) { + mDataInterface = usbInterface; + } + } + + if(mControlInterface == null) { + throw new IOException("no control interface."); + } + Log.d(TAG, "Control iface=" + mControlInterface); + + if (!mConnection.claimInterface(mControlInterface, true)) { + throw new IOException("Could not claim control interface."); + } + + mControlEndpoint = mControlInterface.getEndpoint(0); + if (mControlEndpoint.getDirection() != UsbConstants.USB_DIR_IN || mControlEndpoint.getType() != UsbConstants.USB_ENDPOINT_XFER_INT) { + throw new IOException("invalid control endpoint"); + } + + if(mDataInterface == null) { + throw new IOException("no data interface."); + } + Log.d(TAG, "data iface=" + mDataInterface); + + if (!mConnection.claimInterface(mDataInterface, true)) { + throw new IOException("Could not claim data interface."); + } + + mReadEndpoint = null; + mWriteEndpoint = null; + for (int i = 0; i < mDataInterface.getEndpointCount(); i++) { + UsbEndpoint ep = mDataInterface.getEndpoint(i); + if (ep.getDirection() == UsbConstants.USB_DIR_IN && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) + mReadEndpoint = ep; + if (ep.getDirection() == UsbConstants.USB_DIR_OUT && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) + mWriteEndpoint = ep; + } + if (mReadEndpoint == null || mWriteEndpoint == null) { + throw new IOException("Could not get read&write endpoints."); + } + } + + private int sendAcmControlMessage(int request, int value, byte[] buf) throws IOException { + int len = mConnection.controlTransfer( + USB_RT_ACM, request, value, mControlIndex, buf, buf != null ? buf.length : 0, 5000); + if(len < 0) { + throw new IOException("controlTransfer failed."); + } + return len; + } + + @Override + public void close() throws IOException { + if (mConnection == null) { + throw new IOException("Already closed"); + } + synchronized (this) { + if (mUsbRequest != null) + mUsbRequest.cancel(); + } + mControlEndpoint = null; + mReadEndpoint = null; + mWriteEndpoint = null; + try { + mConnection.releaseInterface(mControlInterface); + mConnection.releaseInterface(mDataInterface); + } catch(Exception ignored) {} + try { + mConnection.close(); + } finally { + mConnection = null; + } + } + + @Override + public int read(byte[] dest, int timeoutMillis) throws IOException { + if(mConnection == null) { + throw new IOException("Connection closed"); + } + final UsbRequest request = new UsbRequest(); + try { + request.initialize(mConnection, mReadEndpoint); + final ByteBuffer buf = ByteBuffer.wrap(dest); + if (!request.queue(buf, dest.length)) { + throw new IOException("Error queueing request."); + } + mUsbRequest = request; + final UsbRequest response = mConnection.requestWait(); + synchronized (this) { + mUsbRequest = null; + } + if (response == null) { + throw new IOException("Null response"); + } + + final int nread = buf.position(); + if (nread > 0) { + //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length))); + return nread; + } else { + return 0; + } + } finally { + mUsbRequest = null; + request.close(); + } + } + + @Override + public int write(byte[] src, int timeoutMillis) throws IOException { + // TODO(mikey): Nearly identical to FtdiSerial write. Refactor. + int offset = 0; + + if(mConnection == null) { + throw new IOException("Connection closed"); + } + while (offset < src.length) { + final int writeLength; + final int amtWritten; + + 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); + } + if (amtWritten <= 0) { + throw new IOException("Error writing " + writeLength + + " bytes at offset " + offset + " length=" + src.length); + } + + Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength); + offset += amtWritten; + } + return offset; + } + + @Override + public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException { + byte stopBitsByte; + switch (stopBits) { + case STOPBITS_1: stopBitsByte = 0; break; + case STOPBITS_1_5: stopBitsByte = 1; break; + case STOPBITS_2: stopBitsByte = 2; break; + default: throw new IllegalArgumentException("Bad value for stopBits: " + stopBits); + } + + byte parityBitesByte; + switch (parity) { + case PARITY_NONE: parityBitesByte = 0; break; + case PARITY_ODD: parityBitesByte = 1; break; + case PARITY_EVEN: parityBitesByte = 2; break; + case PARITY_MARK: parityBitesByte = 3; break; + case PARITY_SPACE: parityBitesByte = 4; break; + default: throw new IllegalArgumentException("Bad value for parity: " + parity); + } + + byte[] msg = { + (byte) ( baudRate & 0xff), + (byte) ((baudRate >> 8 ) & 0xff), + (byte) ((baudRate >> 16) & 0xff), + (byte) ((baudRate >> 24) & 0xff), + stopBitsByte, + parityBitesByte, + (byte) dataBits}; + sendAcmControlMessage(SET_LINE_CODING, 0, msg); + } + + @Override + public boolean getCD() throws IOException { + return false; // TODO + } + + @Override + public boolean getCTS() throws IOException { + return false; // TODO + } + + @Override + public boolean getDSR() throws IOException { + return false; // TODO + } + + @Override + public boolean getDTR() throws IOException { + return mDtr; + } + + @Override + public void setDTR(boolean value) throws IOException { + mDtr = value; + setDtrRts(); + } + + @Override + public boolean getRI() throws IOException { + return false; // TODO + } + + @Override + public boolean getRTS() throws IOException { + return mRts; + } + + @Override + public void setRTS(boolean value) throws IOException { + mRts = value; + setDtrRts(); + } + + private void setDtrRts() throws IOException { + int value = (mRts ? 0x2 : 0) | (mDtr ? 0x1 : 0); + sendAcmControlMessage(SET_CONTROL_LINE_STATE, value, null); + } + + } + + public static Map getSupportedDevices() { + final Map supportedDevices = new LinkedHashMap(); + supportedDevices.put(UsbId.VENDOR_ARDUINO, + new int[] { + UsbId.ARDUINO_UNO, + UsbId.ARDUINO_UNO_R3, + UsbId.ARDUINO_MEGA_2560, + UsbId.ARDUINO_MEGA_2560_R3, + UsbId.ARDUINO_SERIAL_ADAPTER, + UsbId.ARDUINO_SERIAL_ADAPTER_R3, + UsbId.ARDUINO_MEGA_ADK, + UsbId.ARDUINO_MEGA_ADK_R3, + UsbId.ARDUINO_LEONARDO, + UsbId.ARDUINO_MICRO, + }); + supportedDevices.put(UsbId.VENDOR_VAN_OOIJEN_TECH, + new int[] { + UsbId.VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL, + }); + supportedDevices.put(UsbId.VENDOR_ATMEL, + new int[] { + UsbId.ATMEL_LUFA_CDC_DEMO_APP, + }); + supportedDevices.put(UsbId.VENDOR_LEAFLABS, + new int[] { + UsbId.LEAFLABS_MAPLE, + }); + supportedDevices.put(UsbId.VENDOR_ARM, + new int[] { + UsbId.ARM_MBED, + }); + return supportedDevices; + } + +} diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java index 7b36171..0c7e16e 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java @@ -130,11 +130,7 @@ public class Ch34xSerialDriver implements UsbSerialDriver { opened = true; } finally { if (!opened) { - try { - close(); - } catch (IOException e) { - // Ignore IOExceptions during close() - } + close(); } } } @@ -162,10 +158,11 @@ public class Ch34xSerialDriver implements UsbSerialDriver { @Override public int read(byte[] dest, int timeoutMillis) throws IOException { + if(mConnection == null) { + throw new IOException("Connection closed"); + } final UsbRequest request = new UsbRequest(); try { - if(mConnection == null) - throw new IOException("Connection closed"); request.initialize(mConnection, mReadEndpoint); final ByteBuffer buf = ByteBuffer.wrap(dest); if (!request.queue(buf, dest.length)) { @@ -197,6 +194,9 @@ public class Ch34xSerialDriver implements UsbSerialDriver { public int write(byte[] src, int timeoutMillis) throws IOException { int offset = 0; + if(mConnection == null) { + throw new IOException("Connection closed"); + } while (offset < src.length) { final int writeLength; final int amtWritten; diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java index 11d9823..ae572f7 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java @@ -123,9 +123,13 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { return Cp21xxSerialDriver.this; } - private int setConfigSingle(int request, int value) { - return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, value, + private int setConfigSingle(int request, int value) throws IOException { + int result = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, value, mPortNumber, null, 0, USB_WRITE_TIMEOUT_MILLIS); + if (result != 0) { + throw new IOException("Setting baudrate failed: result=" + result); + } + return result; } @Override @@ -163,11 +167,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { opened = true; } finally { if (!opened) { - try { - close(); - } catch (IOException e) { - // Ignore IOExceptions during close() - } + close(); } } } @@ -197,10 +197,11 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { @Override public int read(byte[] dest, int timeoutMillis) throws IOException { + if(mConnection == null) { + throw new IOException("Connection closed"); + } final UsbRequest request = new UsbRequest(); try { - if(mConnection == null) - throw new IOException("Connection closed"); request.initialize(mConnection, mReadEndpoint); final ByteBuffer buf = ByteBuffer.wrap(dest); if (!request.queue(buf, dest.length)) { @@ -232,6 +233,9 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { public int write(byte[] src, int timeoutMillis) throws IOException { int offset = 0; + if(mConnection == null) { + throw new IOException("Connection closed"); + } while (offset < src.length) { final int writeLength; final int amtWritten; 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 8dbdfd4..caffdb9 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 @@ -257,7 +257,6 @@ public class FtdiSerialDriver implements UsbSerialDriver { } finally { if (!opened) { close(); - mConnection = null; } } } @@ -279,12 +278,13 @@ public class FtdiSerialDriver implements UsbSerialDriver { @Override public int read(byte[] dest, int timeoutMillis) throws IOException { + if(mConnection == null) { + throw new IOException("Connection closed"); + } final UsbEndpoint endpoint = mDevice.getInterface(mPortNumber).getEndpoint(0); final UsbRequest request = new UsbRequest(); final ByteBuffer buf = ByteBuffer.wrap(dest); try { - if(mConnection == null) - throw new IOException("Connection closed"); request.initialize(mConnection, endpoint); if (!request.queue(buf, dest.length)) { throw new IOException("Error queueing request."); @@ -308,6 +308,9 @@ public class FtdiSerialDriver implements UsbSerialDriver { @Override public int write(byte[] src, int timeoutMillis) throws IOException { + if(mConnection == null) { + throw new IOException("Connection closed"); + } final UsbEndpoint endpoint = mDevice.getInterface(mPortNumber).getEndpoint(1); int offset = 0; diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProbeTable.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProbeTable.java index db08019..4837366 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProbeTable.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProbeTable.java @@ -65,25 +65,19 @@ public class ProbeTable { try { method = driverClass.getMethod("getSupportedDevices"); - } catch (SecurityException e) { - throw new RuntimeException(e); - } catch (NoSuchMethodException e) { + } catch (SecurityException | NoSuchMethodException e) { throw new RuntimeException(e); } final Map devices; try { devices = (Map) method.invoke(null); - } catch (IllegalArgumentException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { + } catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } for (Map.Entry entry : devices.entrySet()) { - final int vendorId = entry.getKey().intValue(); + final int vendorId = entry.getKey(); for (int productId : entry.getValue()) { addProduct(vendorId, productId, driverClass); } diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java index d4928fc..fdbb044 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java @@ -336,8 +336,7 @@ public class ProlificSerialDriver implements UsbSerialDriver { opened = true; } finally { if (!opened) { - mConnection = null; - connection.releaseInterface(usbInterface); + close(); } } } @@ -373,10 +372,11 @@ public class ProlificSerialDriver implements UsbSerialDriver { @Override public int read(byte[] dest, int timeoutMillis) throws IOException { + if(mConnection == null) { + throw new IOException("Connection closed"); + } final UsbRequest request = new UsbRequest(); try { - if(mConnection == null) - throw new IOException("Connection closed"); request.initialize(mConnection, mReadEndpoint); final ByteBuffer buf = ByteBuffer.wrap(dest); if (!request.queue(buf, dest.length)) { @@ -404,6 +404,9 @@ public class ProlificSerialDriver implements UsbSerialDriver { public int write(byte[] src, int timeoutMillis) throws IOException { int offset = 0; + if(mConnection == null) { + throw new IOException("Connection closed"); + } while (offset < src.length) { final int writeLength; final int amtWritten; diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbSerialProber.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbSerialProber.java index 333af65..72d3534 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbSerialProber.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbSerialProber.java @@ -95,15 +95,8 @@ public class UsbSerialProber { final Constructor ctor = driverClass.getConstructor(UsbDevice.class); driver = ctor.newInstance(usbDevice); - } catch (NoSuchMethodException e) { - throw new RuntimeException(e); - } catch (IllegalArgumentException e) { - throw new RuntimeException(e); - } catch (InstantiationException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } catch (InvocationTargetException e) { + } catch (NoSuchMethodException | IllegalArgumentException | InstantiationException | + IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); } return driver; From 5c6748e1b8e10d55638298411e498dd65a8a6424 Mon Sep 17 00:00:00 2001 From: kai-morich Date: Sat, 2 Nov 2019 13:08:03 +0100 Subject: [PATCH 4/8] improve setParameter() error handling harmonize exception messages, more UI friendly messages distinguish IllegalArgumentException and UnsupportedOperationException --- .../hoho/android/usbserial/DeviceTest.java | 51 +++++-------------- .../usbserial/driver/CdcAcmSerialDriver.java | 31 ++++++----- .../usbserial/driver/Ch34xSerialDriver.java | 32 ++++++------ .../usbserial/driver/CommonUsbSerialPort.java | 3 +- .../usbserial/driver/Cp21xxSerialDriver.java | 32 ++++++------ .../usbserial/driver/FtdiSerialDriver.java | 18 ++++--- .../driver/ProlificSerialDriver.java | 23 ++++----- .../hoho/android/usbserial/driver/UsbId.java | 2 +- .../usbserial/driver/UsbSerialPort.java | 4 +- .../util/SerialInputOutputManager.java | 6 +-- 10 files changed, 92 insertions(+), 110 deletions(-) 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 377b6dc..75a9a68 100644 --- a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java +++ b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java @@ -553,33 +553,12 @@ public class DeviceTest implements SerialInputOutputManager.Listener { // invalid values try { usbParameters(-1, 8, 1, UsbSerialPort.PARITY_NONE); - if (usbSerialDriver instanceof Ch34xSerialDriver) - ; // todo: add range check in driver - else if (usbSerialDriver instanceof FtdiSerialDriver) - ; // todo: add range check in driver - else if (usbSerialDriver instanceof ProlificSerialDriver) - ; // todo: add range check in driver - else if (usbSerialDriver instanceof Cp21xxSerialDriver) - ; // todo: add range check in driver - else if (usbSerialDriver instanceof CdcAcmSerialDriver) - ; // todo: add range check in driver - else - fail("invalid baudrate 0"); - } catch (IOException ignored) { // cp2105 second port + fail("invalid baud rate"); } catch (IllegalArgumentException ignored) { } try { usbParameters(0, 8, 1, UsbSerialPort.PARITY_NONE); - if (usbSerialDriver instanceof ProlificSerialDriver) - ; // todo: add range check in driver - else if (usbSerialDriver instanceof Cp21xxSerialDriver) - ; // todo: add range check in driver - else if (usbSerialDriver instanceof CdcAcmSerialDriver) - ; // todo: add range check in driver - else - fail("invalid baudrate 0"); - } catch (ArithmeticException ignored) { // ch340 - } catch (IOException ignored) { // cp2105 second port + fail("invalid baud rate"); } catch (IllegalArgumentException ignored) { } try { @@ -593,8 +572,9 @@ public class DeviceTest implements SerialInputOutputManager.Listener { else if (usbSerialDriver instanceof CdcAcmSerialDriver) ; else - fail("invalid baudrate 0"); - } catch (IOException ignored) { // ch340 + fail("invalid baudrate 1"); + } catch (UnsupportedOperationException ignored) { // ch340 + } catch (IOException ignored) { // cp2105 second port } catch (IllegalArgumentException ignored) { } try { @@ -679,12 +659,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { for(int i: new int[] {0, 4, 9}) { try { usbParameters(19200, i, 1, UsbSerialPort.PARITY_NONE); - if (usbSerialDriver instanceof ProlificSerialDriver) - ; // todo: add range check in driver - else if (usbSerialDriver instanceof CdcAcmSerialDriver) - ; // todo: add range check in driver - else - fail("invalid databits "+i); + fail("invalid databits "+i); } catch (IllegalArgumentException ignored) { } } @@ -721,7 +696,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { usbWrite(new byte[]{(byte) 0xff}); data = telnetRead(2); assertThat("19000/7N1", data, equalTo(new byte[]{(byte) 0x80, (byte) 0xff})); - } catch (IllegalArgumentException e) { + } catch (UnsupportedOperationException e) { if(!isCp21xxRestrictedPort) throw e; } @@ -732,7 +707,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { usbWrite(new byte[]{(byte) 0xff}); data = telnetRead(2); assertThat("19000/6N1", data, equalTo(new byte[]{(byte) 0xc0, (byte) 0xff})); - } catch (IllegalArgumentException e) { + } catch (UnsupportedOperationException e) { if (!(isCp21xxRestrictedPort || usbSerialDriver instanceof FtdiSerialDriver)) throw e; } @@ -743,7 +718,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { usbWrite(new byte[] {(byte)0xff}); data = telnetRead(2); assertThat("19000/5N1", data, equalTo(new byte[] {(byte)0xe0, (byte)0xff})); - } catch (IllegalArgumentException e) { + } catch (UnsupportedOperationException e) { if (!(isCp21xxRestrictedPort || usbSerialDriver instanceof FtdiSerialDriver)) throw e; } @@ -774,11 +749,11 @@ public class DeviceTest implements SerialInputOutputManager.Listener { try { usbParameters(19200, 8, 1, UsbSerialPort.PARITY_MARK); fail("parity mark"); - } catch (IllegalArgumentException ignored) {} + } catch (UnsupportedOperationException ignored) {} try { usbParameters(19200, 8, 1, UsbSerialPort.PARITY_SPACE); fail("parity space"); - } catch (IllegalArgumentException ignored) {} + } catch (UnsupportedOperationException ignored) {} return; // test below not possible as it requires unsupported 7 dataBits } @@ -894,7 +869,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { usbWrite(new byte[]{(byte) 0x41, (byte) 0xf9}); data = telnetRead(2); assertThat("19200/8N1", data, equalTo(new byte[]{1, 11})); - } catch(IllegalArgumentException e) { + } catch(UnsupportedOperationException e) { if(!isCp21xxRestrictedPort) throw e; } @@ -902,7 +877,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { usbParameters(19200, 8, UsbSerialPort.STOPBITS_1_5, UsbSerialPort.PARITY_NONE); // todo: could create similar test for 1.5 stopbits, by reading at double speed // but only some devices support 1.5 stopbits and it is basically not used any more - } catch(IllegalArgumentException ignored) { + } catch(UnsupportedOperationException ignored) { } } } diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java index 6d17453..88e297c 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java @@ -134,14 +134,14 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { Log.d(TAG, "data iface=" + mDataInterface); if (!mConnection.claimInterface(mControlInterface, true)) { - throw new IOException("Could not claim shared control/data interface."); + throw new IOException("Could not claim shared control/data interface"); } int endCount = mControlInterface.getEndpointCount(); if (endCount < 3) { Log.d(TAG,"not enough endpoints - need 3. count=" + mControlInterface.getEndpointCount()); - throw new IOException("Insufficient number of endpoints(" + mControlInterface.getEndpointCount() + ")"); + throw new IOException("Insufficient number of endpoints (" + mControlInterface.getEndpointCount() + ")"); } // Analyse endpoints for their properties @@ -198,26 +198,26 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { } if(mControlInterface == null) { - throw new IOException("no control interface."); + throw new IOException("No control interface"); } Log.d(TAG, "Control iface=" + mControlInterface); if (!mConnection.claimInterface(mControlInterface, true)) { - throw new IOException("Could not claim control interface."); + throw new IOException("Could not claim control interface"); } mControlEndpoint = mControlInterface.getEndpoint(0); if (mControlEndpoint.getDirection() != UsbConstants.USB_DIR_IN || mControlEndpoint.getType() != UsbConstants.USB_ENDPOINT_XFER_INT) { - throw new IOException("invalid control endpoint"); + throw new IOException("Invalid control endpoint"); } if(mDataInterface == null) { - throw new IOException("no data interface."); + throw new IOException("No data interface"); } Log.d(TAG, "data iface=" + mDataInterface); if (!mConnection.claimInterface(mDataInterface, true)) { - throw new IOException("Could not claim data interface."); + throw new IOException("Could not claim data interface"); } mReadEndpoint = null; @@ -230,7 +230,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { mWriteEndpoint = ep; } if (mReadEndpoint == null || mWriteEndpoint == null) { - throw new IOException("Could not get read&write endpoints."); + throw new IOException("Could not get read&write endpoints"); } } @@ -238,7 +238,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { int len = mConnection.controlTransfer( USB_RT_ACM, request, value, mControlIndex, buf, buf != null ? buf.length : 0, 5000); if(len < 0) { - throw new IOException("controlTransfer failed."); + throw new IOException("controlTransfer failed"); } return len; } @@ -276,7 +276,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { request.initialize(mConnection, mReadEndpoint); final ByteBuffer buf = ByteBuffer.wrap(dest); if (!request.queue(buf, dest.length)) { - throw new IOException("Error queueing request."); + throw new IOException("Error queueing request"); } mUsbRequest = request; final UsbRequest response = mConnection.requestWait(); @@ -340,12 +340,18 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { @Override public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException { + if(baudRate <= 0) { + throw new IllegalArgumentException("Invalid baud rate: " + baudRate); + } + if(dataBits < DATABITS_5 || dataBits > DATABITS_8) { + throw new IllegalArgumentException("Invalid data bits: " + dataBits); + } byte stopBitsByte; switch (stopBits) { case STOPBITS_1: stopBitsByte = 0; break; case STOPBITS_1_5: stopBitsByte = 1; break; case STOPBITS_2: stopBitsByte = 2; break; - default: throw new IllegalArgumentException("Bad value for stopBits: " + stopBits); + default: throw new IllegalArgumentException("Invalid stop bits: " + stopBits); } byte parityBitesByte; @@ -355,9 +361,8 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { case PARITY_EVEN: parityBitesByte = 2; break; case PARITY_MARK: parityBitesByte = 3; break; case PARITY_SPACE: parityBitesByte = 4; break; - default: throw new IllegalArgumentException("Bad value for parity: " + parity); + default: throw new IllegalArgumentException("Invalid parity: " + parity); } - byte[] msg = { (byte) ( baudRate & 0xff), (byte) ((baudRate >> 8 ) & 0xff), diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java index 0c7e16e..0c21001 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java @@ -99,7 +99,7 @@ public class Ch34xSerialDriver implements UsbSerialDriver { @Override public void open(UsbDeviceConnection connection) throws IOException { if (mConnection != null) { - throw new IOException("Already opened."); + throw new IOException("Already open"); } mConnection = connection; @@ -108,7 +108,7 @@ public class Ch34xSerialDriver implements UsbSerialDriver { for (int i = 0; i < mDevice.getInterfaceCount(); i++) { UsbInterface usbIface = mDevice.getInterface(i); if (!mConnection.claimInterface(usbIface, true)) { - throw new IOException("Could not claim data interface."); + throw new IOException("Could not claim data interface"); } } @@ -166,7 +166,7 @@ public class Ch34xSerialDriver implements UsbSerialDriver { request.initialize(mConnection, mReadEndpoint); final ByteBuffer buf = ByteBuffer.wrap(dest); if (!request.queue(buf, dest.length)) { - throw new IOException("Error queueing request."); + throw new IOException("Error queueing request"); } mUsbRequest = request; final UsbRequest response = mConnection.requestWait(); @@ -275,7 +275,7 @@ public class Ch34xSerialDriver implements UsbSerialDriver { checkState("init #1", 0x5f, 0, new int[]{-1 /* 0x27, 0x30 */, 0x00}); if (controlOut(0xa1, 0, 0) < 0) { - throw new IOException("init failed! #2"); + throw new IOException("Init failed: #2"); } setBaudRate(DEFAULT_BAUD_RATE); @@ -283,13 +283,13 @@ public class Ch34xSerialDriver implements UsbSerialDriver { checkState("init #4", 0x95, 0x2518, new int[]{-1 /* 0x56, c3*/, 0x00}); if (controlOut(0x9a, 0x2518, LCR_ENABLE_RX | LCR_ENABLE_TX | LCR_CS8) < 0) { - throw new IOException("init failed! #5"); + throw new IOException("Init failed: #5"); } checkState("init #6", 0x95, 0x0706, new int[]{0xff, 0xee}); if (controlOut(0xa1, 0x501f, 0xd90a) < 0) { - throw new IOException("init failed! #7"); + throw new IOException("Init failed: #7"); } setBaudRate(DEFAULT_BAUD_RATE); @@ -313,25 +313,27 @@ public class Ch34xSerialDriver implements UsbSerialDriver { } if (factor > 0xfff0) { - throw new IOException("Baudrate " + baudRate + " not supported"); + throw new UnsupportedOperationException("Unsupported baud rate: " + baudRate); } factor = 0x10000 - factor; int ret = controlOut(0x9a, 0x1312, (int) ((factor & 0xff00) | divisor)); if (ret < 0) { - throw new IOException("Error setting baud rate. #1)"); + throw new IOException("Error setting baud rate: #1)"); } ret = controlOut(0x9a, 0x0f2c, (int) (factor & 0xff)); if (ret < 0) { - throw new IOException("Error setting baud rate. #2"); + throw new IOException("Error setting baud rate: #2"); } } @Override - public void setParameters(int baudRate, int dataBits, int stopBits, int parity) - throws IOException { + public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException { + if(baudRate <= 0) { + throw new IllegalArgumentException("Invalid baud rate: " + baudRate); + } setBaudRate(baudRate); int lcr = LCR_ENABLE_RX | LCR_ENABLE_TX; @@ -350,7 +352,7 @@ public class Ch34xSerialDriver implements UsbSerialDriver { lcr |= LCR_CS8; break; default: - throw new IllegalArgumentException("Unknown dataBits value: " + dataBits); + throw new IllegalArgumentException("Invalid data bits: " + dataBits); } switch (parity) { @@ -369,19 +371,19 @@ public class Ch34xSerialDriver implements UsbSerialDriver { lcr |= LCR_ENABLE_PAR | LCR_MARK_SPACE | LCR_PAR_EVEN; break; default: - throw new IllegalArgumentException("Unknown parity value: " + parity); + throw new IllegalArgumentException("Invalid parity: " + parity); } switch (stopBits) { case STOPBITS_1: break; case STOPBITS_1_5: - throw new IllegalArgumentException("Unsupported stopBits value: 1.5"); + throw new UnsupportedOperationException("Unsupported stop bits: 1.5"); case STOPBITS_2: lcr |= LCR_STOP_BITS_2; break; default: - throw new IllegalArgumentException("Unknown stopBits value: " + stopBits); + throw new IllegalArgumentException("Invalid stop bits: " + stopBits); } int ret = controlOut(0x9a, 0x2518, lcr); 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 fb7ddc9..1093b30 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 @@ -132,8 +132,7 @@ abstract class CommonUsbSerialPort implements UsbSerialPort { public abstract int write(final byte[] src, final int timeoutMillis) throws IOException; @Override - public abstract void setParameters( - int baudRate, int dataBits, int stopBits, int parity) throws IOException; + public abstract void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException; @Override public abstract boolean getCD() throws IOException; diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java index ae572f7..4b84ca2 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java @@ -135,7 +135,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { @Override public void open(UsbDeviceConnection connection) throws IOException { if (mConnection != null) { - throw new IOException("Already opened."); + throw new IOException("Already open"); } mConnection = connection; @@ -205,7 +205,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { request.initialize(mConnection, mReadEndpoint); final ByteBuffer buf = ByteBuffer.wrap(dest); if (!request.queue(buf, dest.length)) { - throw new IOException("Error queueing request."); + throw new IOException("Error queueing request"); } mUsbRequest = request; final UsbRequest response = mConnection.requestWait(); @@ -276,37 +276,39 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { int ret = mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, SILABSER_SET_BAUDRATE, 0, mPortNumber, data, 4, USB_WRITE_TIMEOUT_MILLIS); if (ret < 0) { - throw new IOException("Error setting baud rate."); + throw new IOException("Error setting baud rate"); } } @Override - public void setParameters(int baudRate, int dataBits, int stopBits, int parity) - throws IOException { + public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException { + if(baudRate <= 0) { + throw new IllegalArgumentException("Invalid baud rate: " + baudRate); + } setBaudRate(baudRate); int configDataBits = 0; switch (dataBits) { case DATABITS_5: if(mIsRestrictedPort) - throw new IllegalArgumentException("Unsupported dataBits value: " + dataBits); + throw new UnsupportedOperationException("Unsupported data bits: " + dataBits); configDataBits |= 0x0500; break; case DATABITS_6: if(mIsRestrictedPort) - throw new IllegalArgumentException("Unsupported dataBits value: " + dataBits); + throw new UnsupportedOperationException("Unsupported data bits: " + dataBits); configDataBits |= 0x0600; break; case DATABITS_7: if(mIsRestrictedPort) - throw new IllegalArgumentException("Unsupported dataBits value: " + dataBits); + throw new UnsupportedOperationException("Unsupported data bits: " + dataBits); configDataBits |= 0x0700; break; case DATABITS_8: configDataBits |= 0x0800; break; default: - throw new IllegalArgumentException("Unknown dataBits value: " + dataBits); + throw new IllegalArgumentException("Invalid data bits: " + dataBits); } switch (parity) { @@ -320,30 +322,30 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { break; case PARITY_MARK: if(mIsRestrictedPort) - throw new IllegalArgumentException("Unsupported parity value: mark"); + throw new UnsupportedOperationException("Unsupported parity: mark"); configDataBits |= 0x0030; break; case PARITY_SPACE: if(mIsRestrictedPort) - throw new IllegalArgumentException("Unsupported parity value: space"); + throw new UnsupportedOperationException("Unsupported parity: space"); configDataBits |= 0x0040; break; default: - throw new IllegalArgumentException("Unknown parity value: " + parity); + throw new IllegalArgumentException("Invalid parity: " + parity); } switch (stopBits) { case STOPBITS_1: break; case STOPBITS_1_5: - throw new IllegalArgumentException("Unsupported stopBits value: 1.5"); + throw new UnsupportedOperationException("Unsupported stop bits: 1.5"); case STOPBITS_2: if(mIsRestrictedPort) - throw new IllegalArgumentException("Unsupported stopBits value: 2"); + throw new UnsupportedOperationException("Unsupported stop bits: 2"); configDataBits |= 2; break; default: - throw new IllegalArgumentException("Unknown stopBits value: " + stopBits); + throw new IllegalArgumentException("Invalid stop bits: " + stopBits); } setConfigSingle(SILABSER_SET_LINE_CTL_REQUEST_CODE, configDataBits); } 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 caffdb9..2a90a04 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 @@ -287,7 +287,7 @@ public class FtdiSerialDriver implements UsbSerialDriver { try { request.initialize(mConnection, endpoint); if (!request.queue(buf, dest.length)) { - throw new IOException("Error queueing request."); + throw new IOException("Error queueing request"); } final UsbRequest response = mConnection.requestWait(); @@ -360,21 +360,23 @@ public class FtdiSerialDriver implements UsbSerialDriver { } @Override - public void setParameters(int baudRate, int dataBits, int stopBits, int parity) - throws IOException { + public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException { + if(baudRate <= 0) { + throw new IllegalArgumentException("Invalid baud rate: " + baudRate); + } setBaudRate(baudRate); int config = 0; switch (dataBits) { case DATABITS_5: case DATABITS_6: - throw new IllegalArgumentException("Unsupported dataBits value: " + dataBits); + throw new UnsupportedOperationException("Unsupported data bits: " + dataBits); case DATABITS_7: case DATABITS_8: config |= dataBits; break; default: - throw new IllegalArgumentException("Unknown dataBits value: " + dataBits); + throw new IllegalArgumentException("Invalid data bits: " + dataBits); } switch (parity) { @@ -394,7 +396,7 @@ public class FtdiSerialDriver implements UsbSerialDriver { config |= (0x04 << 8); break; default: - throw new IllegalArgumentException("Unknown parity value: " + parity); + throw new IllegalArgumentException("Invalid parity: " + parity); } switch (stopBits) { @@ -402,12 +404,12 @@ public class FtdiSerialDriver implements UsbSerialDriver { config |= (0x00 << 11); break; case STOPBITS_1_5: - throw new IllegalArgumentException("Unsupported stopBits value: 1.5"); + throw new UnsupportedOperationException("Unsupported stop bits: 1.5"); case STOPBITS_2: config |= (0x02 << 11); break; default: - throw new IllegalArgumentException("Unknown stopBits value: " + stopBits); + throw new IllegalArgumentException("Invalid stop bits: " + stopBits); } int result = mConnection.controlTransfer(FTDI_DEVICE_OUT_REQTYPE, diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java index fdbb044..29d5f0f 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java @@ -380,7 +380,7 @@ public class ProlificSerialDriver implements UsbSerialDriver { request.initialize(mConnection, mReadEndpoint); final ByteBuffer buf = ByteBuffer.wrap(dest); if (!request.queue(buf, dest.length)) { - throw new IOException("Error queueing request."); + throw new IOException("Error queueing request"); } final UsbRequest response = mConnection.requestWait(); @@ -439,8 +439,7 @@ public class ProlificSerialDriver implements UsbSerialDriver { } @Override - public void setParameters(int baudRate, int dataBits, int stopBits, - int parity) throws IOException { + public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException { if ((mBaudRate == baudRate) && (mDataBits == dataBits) && (mStopBits == stopBits) && (mParity == parity)) { // Make sure no action is performed if there is nothing to change @@ -449,6 +448,9 @@ public class ProlificSerialDriver implements UsbSerialDriver { byte[] lineRequestData = new byte[7]; + if(baudRate <= 0) { + throw new IllegalArgumentException("Invalid baud rate: " + baudRate); + } lineRequestData[0] = (byte) (baudRate & 0xff); lineRequestData[1] = (byte) ((baudRate >> 8) & 0xff); lineRequestData[2] = (byte) ((baudRate >> 16) & 0xff); @@ -458,44 +460,39 @@ public class ProlificSerialDriver implements UsbSerialDriver { case STOPBITS_1: lineRequestData[4] = 0; break; - case STOPBITS_1_5: lineRequestData[4] = 1; break; - case STOPBITS_2: lineRequestData[4] = 2; break; - default: - throw new IllegalArgumentException("Unknown stopBits value: " + stopBits); + throw new IllegalArgumentException("Invalid stop bits: " + stopBits); } switch (parity) { case PARITY_NONE: lineRequestData[5] = 0; break; - case PARITY_ODD: lineRequestData[5] = 1; break; - case PARITY_EVEN: lineRequestData[5] = 2; break; - case PARITY_MARK: lineRequestData[5] = 3; break; - case PARITY_SPACE: lineRequestData[5] = 4; break; - default: - throw new IllegalArgumentException("Unknown parity value: " + parity); + throw new IllegalArgumentException("Invalid parity: " + parity); } + if(dataBits < DATABITS_5 || dataBits > DATABITS_8) { + throw new IllegalArgumentException("Invalid data bits: " + dataBits); + } lineRequestData[6] = (byte) dataBits; ctrlOut(SET_LINE_REQUEST, 0, 0, lineRequestData); diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbId.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbId.java index 7bba4db..18abf29 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbId.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/UsbId.java @@ -76,7 +76,7 @@ public final class UsbId { public static final int ARM_MBED = 0x0204; private UsbId() { - throw new IllegalAccessError("Non-instantiable class."); + throw new IllegalAccessError("Non-instantiable class"); } } 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 5cd3ca5..a6abf98 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 @@ -145,9 +145,9 @@ public interface UsbSerialPort { * {@link #PARITY_EVEN}, {@link #PARITY_MARK}, or * {@link #PARITY_SPACE}. * @throws IOException on error setting the port parameters + * @throws UnsupportedOperationException if not supported by a specific device */ - public void setParameters( - int baudRate, int dataBits, int stopBits, int parity) throws IOException; + public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException; /** * Gets the CD (Carrier Detect) bit from the underlying UART. 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 1ab3edf..f3f0b14 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 @@ -125,12 +125,12 @@ public class SerialInputOutputManager implements Runnable { public void run() { synchronized (this) { if (getState() != State.STOPPED) { - throw new IllegalStateException("Already running."); + throw new IllegalStateException("Already running"); } mState = State.RUNNING; } - Log.i(TAG, "Running .."); + Log.i(TAG, "Running ..."); try { while (true) { if (getState() != State.RUNNING) { @@ -148,7 +148,7 @@ public class SerialInputOutputManager implements Runnable { } finally { synchronized (this) { mState = State.STOPPED; - Log.i(TAG, "Stopped."); + Log.i(TAG, "Stopped"); } } } From e1b62cf6751374bfdc7b94e201b87bbd063d398d Mon Sep 17 00:00:00 2001 From: kai-morich Date: Sun, 3 Nov 2019 13:59:50 +0100 Subject: [PATCH 5/8] write + purge tests, remove unused read buffer code --- .../hoho/android/usbserial/DeviceTest.java | 151 ++++++++++++++++-- .../usbserial/driver/CommonUsbSerialPort.java | 23 +-- 2 files changed, 141 insertions(+), 33 deletions(-) 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 75a9a68..8fa3932 100644 --- a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java +++ b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java @@ -25,6 +25,7 @@ import android.util.Log; import com.hoho.android.usbserial.driver.CdcAcmSerialDriver; import com.hoho.android.usbserial.driver.Ch34xSerialDriver; +import com.hoho.android.usbserial.driver.CommonUsbSerialPort; import com.hoho.android.usbserial.driver.Cp21xxSerialDriver; import com.hoho.android.usbserial.driver.FtdiSerialDriver; import com.hoho.android.usbserial.driver.ProbeTable; @@ -222,6 +223,33 @@ public class DeviceTest implements SerialInputOutputManager.Listener { telnetClient = null; } + private class TestBuffer { + private byte[] buf; + private int len; + + private TestBuffer(int length) { + len = 0; + buf = new byte[length]; + int i=0; + int j=0; + for(j=0; j 0) { buf.put((byte) telnetReadStream.read()); @@ -337,14 +365,11 @@ public class DeviceTest implements SerialInputOutputManager.Listener { } else { byte[] b1 = new byte[256]; while (System.currentTimeMillis() < end) { - int len = usbSerialPort.read(b1, USB_READ_WAIT / 10); - if (len > 0) { + int len = usbSerialPort.read(b1, USB_READ_WAIT); + if (len > 0) buf.put(b1, 0, len); - } else { - if (expectedLength >= 0 && buf.position() >= expectedLength) - break; - Thread.sleep(1); - } + if (expectedLength >= 0 && buf.position() >= expectedLength) + break; } } byte[] data = new byte[buf.position()]; @@ -907,6 +932,85 @@ public class DeviceTest implements SerialInputOutputManager.Listener { assertEquals(availableDrivers.get(0).getClass(), usbSerialDriver.getClass()); } + @Test + public void writeTimeout() throws Exception { + usbOpen(true); + usbParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); + telnetParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); + + // Basically all devices have a UsbEndpoint.getMaxPacketSize() 64. When the timeout + // in usbSerialPort.write() is reached, some packets have been written and the rest + // is discarded. bulkTransfer() does not return the number written so far, but -1. + // With 115200 baud and 1/2 second timeout, typical values are: + // ch340 6080 of 6144 + // pl2302 5952 of 6144 + // cp2102 6400 of 7168 + // cp2105 6272 of 7168 + // ft232 5952 of 6144 + // ft2232 9728 of 10240 + // arduino 128 of 144 + int timeout = 500; + int len = 0; + int startLen = 1024; + int step = 1024; + int minLen = 4069; + int maxLen = 12288; + int bufferSize = 997; + TestBuffer buf = new TestBuffer(len); + if(usbSerialDriver instanceof CdcAcmSerialDriver) { + startLen = 16; + step = 16; + minLen = 128; + maxLen = 256; + bufferSize = 31; + } + + try { + for (len = startLen; len < maxLen; len += step) { + buf = new TestBuffer(len); + Log.d(TAG, "write buffer size " + len); + usbSerialPort.write(buf.buf, timeout); + while (!buf.testRead(telnetRead(-1))) + ; + } + fail("write timeout expected between " + minLen + " and " + maxLen + ", is " + len); + } catch (IOException e) { + Log.d(TAG, "usbWrite failed", e); + while (true) { + byte[] data = telnetRead(-1); + if (data.length == 0) break; + if (buf.testRead(data)) break; + } + Log.d(TAG, "received " + buf.len + " of " + len + " bytes of failing usbWrite"); + assertTrue("write timeout expected between " + minLen + " and " + maxLen + ", is " + len, len > minLen); + } + + // With smaller writebuffer, the timeout is used per bulkTransfer. + // Should further calls only use the remaining timout? + ((CommonUsbSerialPort) usbSerialPort).setWriteBufferSize(bufferSize); + len = maxLen; + buf = new TestBuffer(len); + Log.d(TAG, "write buffer size " + len); + usbSerialPort.write(buf.buf, timeout); + while (!buf.testRead(telnetRead(-1))) + ; + } + + @Test + public void writeFragments() throws Exception { + usbOpen(true); + usbParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); + telnetParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); + + ((CommonUsbSerialPort) usbSerialPort).setWriteBufferSize(12); + ((CommonUsbSerialPort) usbSerialPort).setWriteBufferSize(12); // keeps last buffer + TestBuffer buf = new TestBuffer(256); + usbSerialPort.write(buf.buf, 5000); + while (!buf.testRead(telnetRead(-1))) + ; + // todo: deduplicate write method, use bulkTransfer with offset + } + @Test // provoke data loss, when data is not read fast enough public void readBufferOverflow() throws Exception { @@ -1077,6 +1181,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { @Test public void purgeHwBuffers() throws Exception { + // purge write buffer // 2400 is slowest baud rate for isCp21xxRestrictedPort usbOpen(true); usbParameters(2400, 8, 1, UsbSerialPort.PARITY_NONE); @@ -1085,9 +1190,8 @@ public class DeviceTest implements SerialInputOutputManager.Listener { for(int i=0; i 1) { + assertThat(usbRead(1), equalTo("y".getBytes())); // cp2105/0 + } else { + assertThat(usbRead(2), equalTo("xy".getBytes())); // cp2102 + } + } else { + assertThat(usbRead(1), equalTo("y".getBytes())); + } + } else { + assertThat(usbRead(2), equalTo("xy".getBytes())); + } } @Test 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 1093b30..8323535 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 @@ -31,9 +31,8 @@ import java.io.IOException; * * @author mike wakerly (opensource@hoho.com) */ -abstract class CommonUsbSerialPort implements UsbSerialPort { +public abstract class CommonUsbSerialPort implements UsbSerialPort { - public static final int DEFAULT_READ_BUFFER_SIZE = 16 * 1024; public static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024; protected final UsbDevice mDevice; @@ -42,12 +41,8 @@ abstract class CommonUsbSerialPort implements UsbSerialPort { // non-null when open() protected UsbDeviceConnection mConnection = null; - 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; @@ -55,7 +50,6 @@ abstract class CommonUsbSerialPort implements UsbSerialPort { mDevice = device; mPortNumber = portNumber; - mReadBuffer = new byte[DEFAULT_READ_BUFFER_SIZE]; mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE]; } @@ -89,21 +83,6 @@ abstract class CommonUsbSerialPort implements UsbSerialPort { return mConnection.getSerial(); } - /** - * 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. From 5767298636fdf0d0d07cb7a6c34f578619ac6917 Mon Sep 17 00:00:00 2001 From: kai-morich Date: Sat, 9 Nov 2019 20:18:47 +0100 Subject: [PATCH 6/8] refactor duplicated read/write methods --- .../usbserial/driver/CdcAcmSerialDriver.java | 77 ------------- .../usbserial/driver/Ch34xSerialDriver.java | 79 -------------- .../usbserial/driver/CommonUsbSerialPort.java | 83 +++++++++++++- .../usbserial/driver/Cp21xxSerialDriver.java | 78 ------------- .../usbserial/driver/FtdiSerialDriver.java | 103 ++++-------------- .../driver/ProlificSerialDriver.java | 72 ------------ 6 files changed, 97 insertions(+), 395 deletions(-) diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java index 88e297c..8efccd7 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java @@ -26,11 +26,9 @@ import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbEndpoint; import android.hardware.usb.UsbInterface; -import android.hardware.usb.UsbRequest; import android.util.Log; import java.io.IOException; -import java.nio.ByteBuffer; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -50,7 +48,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { private final UsbDevice mDevice; private final UsbSerialPort mPort; - private UsbRequest mUsbRequest; public CdcAcmSerialDriver(UsbDevice device) { mDevice = device; @@ -73,8 +70,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { private UsbInterface mDataInterface; private UsbEndpoint mControlEndpoint; - private UsbEndpoint mReadEndpoint; - private UsbEndpoint mWriteEndpoint; private int mControlIndex; @@ -266,78 +261,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { } } - @Override - public int read(byte[] dest, int timeoutMillis) throws IOException { - if(mConnection == null) { - throw new IOException("Connection closed"); - } - final UsbRequest request = new UsbRequest(); - try { - request.initialize(mConnection, mReadEndpoint); - final ByteBuffer buf = ByteBuffer.wrap(dest); - if (!request.queue(buf, dest.length)) { - throw new IOException("Error queueing request"); - } - mUsbRequest = request; - final UsbRequest response = mConnection.requestWait(); - synchronized (this) { - mUsbRequest = null; - } - if (response == null) { - throw new IOException("Null response"); - } - - final int nread = buf.position(); - if (nread > 0) { - //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length))); - return nread; - } else { - return 0; - } - } finally { - mUsbRequest = null; - request.close(); - } - } - - @Override - public int write(byte[] src, int timeoutMillis) throws IOException { - // TODO(mikey): Nearly identical to FtdiSerial write. Refactor. - int offset = 0; - - if(mConnection == null) { - throw new IOException("Connection closed"); - } - while (offset < src.length) { - final int writeLength; - final int amtWritten; - - 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); - } - if (amtWritten <= 0) { - throw new IOException("Error writing " + writeLength - + " bytes at offset " + offset + " length=" + src.length); - } - - Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength); - offset += amtWritten; - } - return offset; - } - @Override public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException { if(baudRate <= 0) { diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java index 0c21001..c6870b8 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java @@ -25,11 +25,8 @@ import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbEndpoint; import android.hardware.usb.UsbInterface; -import android.hardware.usb.UsbRequest; -import android.util.Log; import java.io.IOException; -import java.nio.ByteBuffer; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -83,10 +80,6 @@ public class Ch34xSerialDriver implements UsbSerialDriver { private boolean dtr = false; private boolean rts = false; - private UsbEndpoint mReadEndpoint; - private UsbEndpoint mWriteEndpoint; - private UsbRequest mUsbRequest; - public Ch340SerialPort(UsbDevice device, int portNumber) { super(device, portNumber); } @@ -155,78 +148,6 @@ public class Ch34xSerialDriver implements UsbSerialDriver { } } - - @Override - public int read(byte[] dest, int timeoutMillis) throws IOException { - if(mConnection == null) { - throw new IOException("Connection closed"); - } - final UsbRequest request = new UsbRequest(); - try { - request.initialize(mConnection, mReadEndpoint); - final ByteBuffer buf = ByteBuffer.wrap(dest); - if (!request.queue(buf, dest.length)) { - throw new IOException("Error queueing request"); - } - mUsbRequest = request; - final UsbRequest response = mConnection.requestWait(); - synchronized (this) { - mUsbRequest = null; - } - if (response == null) { - throw new IOException("Null response"); - } - - final int nread = buf.position(); - if (nread > 0) { - //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length))); - return nread; - } else { - return 0; - } - } finally { - mUsbRequest = null; - request.close(); - } - } - - @Override - public int write(byte[] src, int timeoutMillis) throws IOException { - int offset = 0; - - if(mConnection == null) { - throw new IOException("Connection closed"); - } - while (offset < src.length) { - final int writeLength; - final int amtWritten; - - 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); - } - if (amtWritten <= 0) { - throw new IOException("Error writing " + writeLength - + " bytes at offset " + offset + " length=" + src.length); - } - - Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength); - offset += amtWritten; - } - return offset; - } - private int controlOut(int request, int value, int index) { final int REQTYPE_HOST_TO_DEVICE = 0x41; return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request, 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 8323535..cc9797c 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 @@ -23,8 +23,12 @@ package com.hoho.android.usbserial.driver; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; +import android.hardware.usb.UsbEndpoint; +import android.hardware.usb.UsbRequest; +import android.util.Log; import java.io.IOException; +import java.nio.ByteBuffer; /** * A base class shared by several driver implementations. @@ -33,16 +37,19 @@ import java.io.IOException; */ public abstract class CommonUsbSerialPort implements UsbSerialPort { - public static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024; + private static final String TAG = CommonUsbSerialPort.class.getSimpleName(); + private static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024; protected final UsbDevice mDevice; protected final int mPortNumber; // non-null when open() protected UsbDeviceConnection mConnection = null; + protected UsbEndpoint mReadEndpoint; + protected UsbEndpoint mWriteEndpoint; + protected UsbRequest mUsbRequest; protected final Object mWriteBufferLock = new Object(); - /** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */ protected byte[] mWriteBuffer; @@ -52,7 +59,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort { mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE]; } - + @Override public String toString() { return String.format("<%s device_name=%s device_id=%s port_number=%s>", @@ -105,10 +112,76 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort { public abstract void close() throws IOException; @Override - public abstract int read(final byte[] dest, final int timeoutMillis) throws IOException; + public int read(final byte[] dest, final int timeoutMillis) throws IOException { + if(mConnection == null) { + throw new IOException("Connection closed"); + } + final UsbRequest request = new UsbRequest(); + try { + request.initialize(mConnection, mReadEndpoint); + final ByteBuffer buf = ByteBuffer.wrap(dest); + if (!request.queue(buf, dest.length)) { + throw new IOException("Error queueing request"); + } + mUsbRequest = request; + final UsbRequest response = mConnection.requestWait(); + synchronized (this) { + mUsbRequest = null; + } + if (response == null) { + throw new IOException("Null response"); + } + final int nread = buf.position(); + if (nread > 0) { + return readFilter(dest, nread); + } else { + return 0; + } + } finally { + mUsbRequest = null; + request.close(); + } + } + + protected int readFilter(final byte[] buffer, int len) throws IOException { return len; } @Override - public abstract int write(final byte[] src, final int timeoutMillis) throws IOException; + public int write(final byte[] src, final int timeoutMillis) throws IOException { + int offset = 0; + + if(mConnection == null) { + throw new IOException("Connection closed"); + } + while (offset < src.length) { + final int writeLength; + final int amtWritten; + + 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); + } + if (amtWritten <= 0) { + throw new IOException("Error writing " + writeLength + + " bytes at offset " + offset + " length=" + src.length); + } + + Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength); + offset += amtWritten; + } + return offset; + } + @Override public abstract void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException; diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java index 4b84ca2..a148b43 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java @@ -26,11 +26,8 @@ import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbEndpoint; import android.hardware.usb.UsbInterface; -import android.hardware.usb.UsbRequest; -import android.util.Log; import java.io.IOException; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -106,10 +103,6 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { private static final int CONTROL_WRITE_DTR = 0x0100; private static final int CONTROL_WRITE_RTS = 0x0200; - private UsbEndpoint mReadEndpoint; - private UsbEndpoint mWriteEndpoint; - private UsbRequest mUsbRequest; - // second port of Cp2105 has limited baudRate, dataBits, stopBits, parity // unsupported baudrate returns error at controlTransfer(), other parameters are silently ignored private boolean mIsRestrictedPort; @@ -195,77 +188,6 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { } } - @Override - public int read(byte[] dest, int timeoutMillis) throws IOException { - if(mConnection == null) { - throw new IOException("Connection closed"); - } - final UsbRequest request = new UsbRequest(); - try { - request.initialize(mConnection, mReadEndpoint); - final ByteBuffer buf = ByteBuffer.wrap(dest); - if (!request.queue(buf, dest.length)) { - throw new IOException("Error queueing request"); - } - mUsbRequest = request; - final UsbRequest response = mConnection.requestWait(); - synchronized (this) { - mUsbRequest = null; - } - if (response == null) { - throw new IOException("Null response"); - } - - final int nread = buf.position(); - if (nread > 0) { - //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length))); - return nread; - } else { - return 0; - } - } finally { - mUsbRequest = null; - request.close(); - } - } - - @Override - public int write(byte[] src, int timeoutMillis) throws IOException { - int offset = 0; - - if(mConnection == null) { - throw new IOException("Connection closed"); - } - while (offset < src.length) { - final int writeLength; - final int amtWritten; - - 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); - } - if (amtWritten <= 0) { - throw new IOException("Error writing " + writeLength - + " bytes at offset " + offset + " length=" + src.length); - } - - Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength); - offset += amtWritten; - } - return offset; - } - private void setBaudRate(int baudRate) throws IOException { byte[] data = new byte[] { (byte) ( baudRate & 0xff), 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 2a90a04..e0162c3 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 @@ -24,12 +24,9 @@ package com.hoho.android.usbserial.driver; import android.hardware.usb.UsbConstants; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; -import android.hardware.usb.UsbEndpoint; -import android.hardware.usb.UsbRequest; import android.util.Log; import java.io.IOException; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -196,31 +193,32 @@ public class FtdiSerialDriver implements UsbSerialDriver { /** * Filter FTDI status bytes from buffer - * @param src The source buffer (which contains status bytes) - * @param dest The destination buffer to write the status bytes into (can be src) + * @param buffer The source buffer (which contains status bytes) + * buffer The destination buffer to write the status bytes into (can be src) * @param totalBytesRead Number of bytes read to src - * @param maxPacketSize The USB endpoint max packet size * @return The number of payload bytes */ - private final int filterStatusBytes(byte[] src, byte[] dest, int totalBytesRead, int maxPacketSize) { + @Override + protected int readFilter(byte[] buffer, int totalBytesRead) throws IOException { + if (totalBytesRead < MODEM_STATUS_HEADER_LENGTH) { + throw new IOException("Expected at least " + MODEM_STATUS_HEADER_LENGTH + " bytes"); + } + int maxPacketSize = mReadEndpoint.getMaxPacketSize(); final int packetsCount = (totalBytesRead + maxPacketSize -1 )/ maxPacketSize; for (int packetIdx = 0; packetIdx < packetsCount; ++packetIdx) { final int count = (packetIdx == (packetsCount - 1)) ? totalBytesRead - packetIdx * maxPacketSize - MODEM_STATUS_HEADER_LENGTH : maxPacketSize - MODEM_STATUS_HEADER_LENGTH; if (count > 0) { - System.arraycopy(src, - packetIdx * maxPacketSize + MODEM_STATUS_HEADER_LENGTH, - dest, - packetIdx * (maxPacketSize - MODEM_STATUS_HEADER_LENGTH), - count); + System.arraycopy(buffer, packetIdx * maxPacketSize + MODEM_STATUS_HEADER_LENGTH, + buffer, packetIdx * (maxPacketSize - MODEM_STATUS_HEADER_LENGTH), + count); } } - - return totalBytesRead - (packetsCount * 2); + return totalBytesRead - (packetsCount * 2); } - public void reset() throws IOException { + void reset() throws IOException { // TODO(mikey): autodetect. mType = DeviceType.TYPE_R; if(mDevice.getInterfaceCount() > 1) { @@ -252,6 +250,12 @@ public class FtdiSerialDriver implements UsbSerialDriver { } else { throw new IOException("Error claiming interface " + mPortNumber); } + if (mDevice.getInterface(mPortNumber).getEndpointCount() < 2) { + throw new IOException("Insufficient number of endpoints (" + + mDevice.getInterface(mPortNumber).getEndpointCount() + ")"); + } + mReadEndpoint = mDevice.getInterface(mPortNumber).getEndpoint(0); + mWriteEndpoint = mDevice.getInterface(mPortNumber).getEndpoint(1); reset(); opened = true; } finally { @@ -276,75 +280,6 @@ public class FtdiSerialDriver implements UsbSerialDriver { } } - @Override - public int read(byte[] dest, int timeoutMillis) throws IOException { - if(mConnection == null) { - throw new IOException("Connection closed"); - } - final UsbEndpoint endpoint = mDevice.getInterface(mPortNumber).getEndpoint(0); - final UsbRequest request = new UsbRequest(); - final ByteBuffer buf = ByteBuffer.wrap(dest); - try { - request.initialize(mConnection, endpoint); - if (!request.queue(buf, dest.length)) { - throw new IOException("Error queueing request"); - } - - final UsbRequest response = mConnection.requestWait(); - if (response == null) { - throw new IOException("Null response"); - } - } finally { - request.close(); - } - - final int totalBytesRead = buf.position(); - if (totalBytesRead < MODEM_STATUS_HEADER_LENGTH) { - throw new IOException("Expected at least " + MODEM_STATUS_HEADER_LENGTH + " bytes"); - } - - return filterStatusBytes(dest, dest, totalBytesRead, endpoint.getMaxPacketSize()); - } - - @Override - public int write(byte[] src, int timeoutMillis) throws IOException { - if(mConnection == null) { - throw new IOException("Connection closed"); - } - final UsbEndpoint endpoint = mDevice.getInterface(mPortNumber).getEndpoint(1); - int offset = 0; - - while (offset < src.length) { - final int writeLength; - final int amtWritten; - - 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); - } - - if (amtWritten <= 0) { - throw new IOException("Error writing " + writeLength - + " bytes at offset " + offset + " length=" + src.length); - } - - Log.d(TAG, "Wrote amtWritten=" + amtWritten + " attempted=" + writeLength); - offset += amtWritten; - } - return offset; - } - private int setBaudRate(int baudRate) throws IOException { long[] vals = convertBaudrate(baudRate); long actualBaudrate = vals[0]; diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java index 29d5f0f..ba084ad 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java @@ -32,12 +32,10 @@ import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbEndpoint; import android.hardware.usb.UsbInterface; -import android.hardware.usb.UsbRequest; import android.util.Log; import java.io.IOException; import java.lang.reflect.Method; -import java.nio.ByteBuffer; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -111,8 +109,6 @@ public class ProlificSerialDriver implements UsbSerialDriver { private int mDeviceType = DEVICE_TYPE_HX; - private UsbEndpoint mReadEndpoint; - private UsbEndpoint mWriteEndpoint; private UsbEndpoint mInterruptEndpoint; private int mControlLinesValue = 0; @@ -370,74 +366,6 @@ public class ProlificSerialDriver implements UsbSerialDriver { } } - @Override - public int read(byte[] dest, int timeoutMillis) throws IOException { - if(mConnection == null) { - throw new IOException("Connection closed"); - } - final UsbRequest request = new UsbRequest(); - try { - request.initialize(mConnection, mReadEndpoint); - final ByteBuffer buf = ByteBuffer.wrap(dest); - if (!request.queue(buf, dest.length)) { - throw new IOException("Error queueing request"); - } - - final UsbRequest response = mConnection.requestWait(); - if (response == null) { - throw new IOException("Null response"); - } - - final int nread = buf.position(); - if (nread > 0) { - //Log.d(TAG, HexDump.dumpHexString(dest, 0, Math.min(32, dest.length))); - return nread; - } else { - return 0; - } - } finally { - request.close(); - } - } - - @Override - public int write(byte[] src, int timeoutMillis) throws IOException { - int offset = 0; - - if(mConnection == null) { - throw new IOException("Connection closed"); - } - while (offset < src.length) { - final int writeLength; - final int amtWritten; - - 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); - } - - if (amtWritten <= 0) { - throw new IOException("Error writing " + writeLength - + " bytes at offset " + offset + " length=" - + src.length); - } - - offset += amtWritten; - } - return offset; - } - @Override public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException { if ((mBaudRate == baudRate) && (mDataBits == dataBits) From 24187b3af604a832ef9722480dfd9bf907ab7132 Mon Sep 17 00:00:00 2001 From: kai-morich Date: Sat, 9 Nov 2019 22:48:00 +0100 Subject: [PATCH 7/8] refactor duplicated code in close method --- .../usbserial/driver/CdcAcmSerialDriver.java | 17 +-------------- .../usbserial/driver/Ch34xSerialDriver.java | 14 +------------ .../usbserial/driver/CommonUsbSerialPort.java | 21 ++++++++++++++++++- .../usbserial/driver/Cp21xxSerialDriver.java | 15 +------------ .../usbserial/driver/FtdiSerialDriver.java | 10 +-------- .../driver/ProlificSerialDriver.java | 19 +++++------------ 6 files changed, 29 insertions(+), 67 deletions(-) diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java index 8efccd7..a2825f1 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/CdcAcmSerialDriver.java @@ -239,26 +239,11 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { } @Override - public void close() throws IOException { - if (mConnection == null) { - throw new IOException("Already closed"); - } - synchronized (this) { - if (mUsbRequest != null) - mUsbRequest.cancel(); - } - mControlEndpoint = null; - mReadEndpoint = null; - mWriteEndpoint = null; + public void closeInt() { try { mConnection.releaseInterface(mControlInterface); mConnection.releaseInterface(mDataInterface); } catch(Exception ignored) {} - try { - mConnection.close(); - } finally { - mConnection = null; - } } @Override diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java index c6870b8..481827f 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Ch34xSerialDriver.java @@ -129,23 +129,11 @@ public class Ch34xSerialDriver implements UsbSerialDriver { } @Override - public void close() throws IOException { - if (mConnection == null) { - throw new IOException("Already closed"); - } - synchronized (this) { - if (mUsbRequest != null) - mUsbRequest.cancel(); - } + public void closeInt() { try { for (int i = 0; i < mDevice.getInterfaceCount(); i++) mConnection.releaseInterface(mDevice.getInterface(i)); } catch(Exception ignored) {} - try { - mConnection.close(); - } finally { - mConnection = null; - } } private int controlOut(int request, int value, int index) { 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 cc9797c..b1cca5f 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 @@ -109,7 +109,26 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort { public abstract void open(UsbDeviceConnection connection) throws IOException; @Override - public abstract void close() throws IOException; + public void close() throws IOException { + if (mConnection == null) { + throw new IOException("Already closed"); + } + synchronized (this) { + if (mUsbRequest != null) + mUsbRequest.cancel(); + } + try { + closeInt(); + } catch(Exception ignored) {} + try { + mConnection.close(); + } finally { + mConnection = null; + } + + } + + protected abstract void closeInt(); @Override public int read(final byte[] dest, final int timeoutMillis) throws IOException { diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java index a148b43..5334f42 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/Cp21xxSerialDriver.java @@ -166,26 +166,13 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { } @Override - public void close() throws IOException { - if (mConnection == null) { - throw new IOException("Already closed"); - } - synchronized (this) { - if(mUsbRequest != null) { - mUsbRequest.cancel(); - } - } + public void closeInt() { try { setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE); } catch (Exception ignored) {} try { mConnection.releaseInterface(mDevice.getInterface(mPortNumber)); } catch(Exception ignored) {} - try { - mConnection.close(); - } finally { - mConnection = null; - } } private void setBaudRate(int baudRate) throws IOException { 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 e0162c3..4df1857 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 @@ -266,18 +266,10 @@ public class FtdiSerialDriver implements UsbSerialDriver { } @Override - public void close() throws IOException { - if (mConnection == null) { - throw new IOException("Already closed"); - } + public void closeInt() { try { mConnection.releaseInterface(mDevice.getInterface(mPortNumber)); } catch(Exception ignored) {} - try { - mConnection.close(); - } finally { - mConnection = null; - } } private int setBaudRate(int baudRate) throws IOException { diff --git a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java index ba084ad..b581702 100644 --- a/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java +++ b/usbSerialForAndroid/src/main/java/com/hoho/android/usbserial/driver/ProlificSerialDriver.java @@ -338,10 +338,7 @@ public class ProlificSerialDriver implements UsbSerialDriver { } @Override - public void close() throws IOException { - if (mConnection == null) { - throw new IOException("Already closed"); - } + public void closeInt() { try { mStopReadStatusThread = true; synchronized (mReadStatusThreadLock) { @@ -354,16 +351,10 @@ public class ProlificSerialDriver implements UsbSerialDriver { } } resetDevice(); - } finally { - try { - mConnection.releaseInterface(mDevice.getInterface(0)); - } catch(Exception ignored) {} - try { - mConnection.close(); - } finally { - mConnection = null; - } - } + } catch(Exception ignored) {} + try { + mConnection.releaseInterface(mDevice.getInterface(0)); + } catch(Exception ignored) {} } @Override From fd2055791ae045e89ff0c7209e376de4efd8fdef Mon Sep 17 00:00:00 2001 From: kai-morich Date: Wed, 13 Nov 2019 07:47:04 +0100 Subject: [PATCH 8/8] added proguard rules now they are part of the .aar library, before you had to add them to each release app --- usbSerialForAndroid/build.gradle | 9 ++------- usbSerialForAndroid/proguard-rules.pro | 1 + usbSerialForAndroid/publishToMavenLocal.gradle | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) create mode 100644 usbSerialForAndroid/proguard-rules.pro diff --git a/usbSerialForAndroid/build.gradle b/usbSerialForAndroid/build.gradle index 5aa0170..bf1bde1 100644 --- a/usbSerialForAndroid/build.gradle +++ b/usbSerialForAndroid/build.gradle @@ -7,19 +7,14 @@ android { defaultConfig { minSdkVersion 17 targetSdkVersion 28 + consumerProguardFiles 'proguard-rules.pro' + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunnerArguments = [ // Raspi Windows LinuxVM ... 'rfc2217_server_host': '192.168.0.100', 'rfc2217_server_nonstandard_baudrates': 'true', // true false false ] } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' - } - } } dependencies { diff --git a/usbSerialForAndroid/proguard-rules.pro b/usbSerialForAndroid/proguard-rules.pro new file mode 100644 index 0000000..102a90a --- /dev/null +++ b/usbSerialForAndroid/proguard-rules.pro @@ -0,0 +1 @@ +-keep class com.hoho.android.usbserial.driver.* { *; } diff --git a/usbSerialForAndroid/publishToMavenLocal.gradle b/usbSerialForAndroid/publishToMavenLocal.gradle index 1212e0d..a007e7b 100644 --- a/usbSerialForAndroid/publishToMavenLocal.gradle +++ b/usbSerialForAndroid/publishToMavenLocal.gradle @@ -5,7 +5,7 @@ publishing { maven(MavenPublication) { groupId 'com.github.mik3y' artifactId 'usb-serial-for-android' - version '1.x.0' + version '2.1.0a' afterEvaluate { artifact androidSourcesJar artifact bundleReleaseAar