diff --git a/build.gradle b/build.gradle index cddb2c1..371057a 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:7.1.3' + classpath 'com.android.tools.build:gradle:7.0.4' } } diff --git a/gradle.properties b/gradle.properties index 399f577..dbb7bf7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -#android.enableJetifier=true +android.enableJetifier=true android.useAndroidX=true diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b842c72..ff912a2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip diff --git a/usbSerialExamples/build.gradle b/usbSerialExamples/build.gradle index 9b27189..cb15d39 100644 --- a/usbSerialExamples/build.gradle +++ b/usbSerialExamples/build.gradle @@ -15,7 +15,6 @@ android { targetSdkVersion 31 vectorDrawables.useSupportLibrary = true - testInstrumentationRunner "android.test.InstrumentationTestRunner" missingDimensionStrategy 'device', 'anyDevice' } diff --git a/usbSerialForAndroid/build.gradle b/usbSerialForAndroid/build.gradle index 98962d5..3e4964b 100644 --- a/usbSerialForAndroid/build.gradle +++ b/usbSerialForAndroid/build.gradle @@ -11,7 +11,7 @@ android { targetSdkVersion 31 consumerProguardFiles 'proguard-rules.pro' - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunnerArguments = [ // Raspi Windows LinuxVM ... 'rfc2217_server_host': '192.168.0.100', 'rfc2217_server_nonstandard_baudrates': 'true', // true false false @@ -25,9 +25,10 @@ android { dependencies { implementation "androidx.annotation:annotation:1.3.0" + implementation 'androidx.test:core:1.4.0' testImplementation 'junit:junit:4.13.2' testImplementation 'org.mockito:mockito-core:1.10.19' - androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'androidx.test:runner:1.4.0' androidTestImplementation 'commons-net:commons-net:3.8.0' androidTestImplementation 'org.apache.commons:commons-lang3:3.11' } @@ -37,7 +38,7 @@ project.afterEvaluate { publishing { publications { release(MavenPublication) { - from components.release + from components.release // change to anyDeviceRelease if coverage is enabled artifact androidSourcesJar // values used for local maven repo, jitpack uses github release: diff --git a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/CrossoverTest.java b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/CrossoverTest.java index 07b2f9c..4db576d 100644 --- a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/CrossoverTest.java +++ b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/CrossoverTest.java @@ -7,8 +7,9 @@ package com.hoho.android.usbserial; import android.content.Context; import android.hardware.usb.UsbManager; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import android.util.Log; import com.hoho.android.usbserial.driver.UsbSerialDriver; @@ -58,7 +59,7 @@ public class CrossoverTest { assumeTrue("ignore test for device specific coverage report", InstrumentationRegistry.getArguments().getString("test_device_driver") == null); - context = InstrumentationRegistry.getContext(); + context = ApplicationProvider.getApplicationContext(); usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); List availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(usbManager); assertNotEquals("no USB device found", 0, availableDrivers.size()); 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 19db649..e7342dd 100644 --- a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java +++ b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java @@ -15,20 +15,21 @@ import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbManager; import android.os.Process; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; 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.CommonUsbSerialPortWrapper; import com.hoho.android.usbserial.driver.Cp21xxSerialDriver; import com.hoho.android.usbserial.driver.FtdiSerialDriver; import com.hoho.android.usbserial.driver.ProbeTable; import com.hoho.android.usbserial.driver.ProlificSerialDriver; -import com.hoho.android.usbserial.driver.ProlificWrapper; +import com.hoho.android.usbserial.driver.ProlificSerialPortWrapper; import com.hoho.android.usbserial.driver.SerialTimeoutException; -import com.hoho.android.usbserial.driver.UsbId; import com.hoho.android.usbserial.driver.UsbSerialDriver; import com.hoho.android.usbserial.driver.UsbSerialPort; import com.hoho.android.usbserial.driver.UsbSerialProber; @@ -36,6 +37,8 @@ import com.hoho.android.usbserial.util.SerialInputOutputManager; import com.hoho.android.usbserial.util.TelnetWrapper; import com.hoho.android.usbserial.util.TestBuffer; import com.hoho.android.usbserial.util.UsbWrapper; +import com.hoho.android.usbserial.driver.UsbSerialPort.ControlLine; + import org.junit.After; import org.junit.AfterClass; @@ -86,7 +89,6 @@ public class DeviceTest { private UsbManager usbManager; UsbWrapper usb; static TelnetWrapper telnet; - private boolean isCp21xxRestrictedPort = false; // second port of Cp2105 has limited dataBits, stopBits, parity @Rule public TestRule watcher = new TestWatcher() { @@ -111,7 +113,7 @@ public class DeviceTest { public void setUp() throws Exception { telnet.setUp(); - context = InstrumentationRegistry.getContext(); + context = ApplicationProvider.getApplicationContext(); usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); List availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(usbManager); if(availableDrivers.isEmpty()) { @@ -130,7 +132,6 @@ public class DeviceTest { usb.setUp(); Log.i(TAG, "Using USB device "+ usb.serialPort.toString()+" driver="+usb.serialDriver.getClass().getSimpleName()); - isCp21xxRestrictedPort = usb.serialDriver instanceof Cp21xxSerialDriver && usb.serialDriver.getPorts().size()==2 && test_device_port == 1; telnet.read(-1); // doesn't look related here, but very often after usb permission dialog the first test failed with telnet garbage } @@ -202,7 +203,7 @@ public class DeviceTest { doReadWrite(reason, -1); } private void doReadWrite(String reason, int readWait) throws Exception { - byte[] buf1 = new byte[]{ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x55, 0x55}; + byte[] buf1 = new byte[]{ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x55, 0x55}; byte[] buf2 = new byte[]{ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x55, 0x55}; byte[] data; @@ -296,9 +297,9 @@ public class DeviceTest { 403200, 460800, 614400, 806400, 921600, 1228800, 2457600, 3000000, /*6000000*/ }; usb.open(); - Assume.assumeFalse("only for non PL2303G*", ProlificWrapper.isDeviceTypeHxn(usb.serialPort)); // HXN does not use divisor + Assume.assumeFalse("only for non PL2303G*", ProlificSerialPortWrapper.isDeviceTypeHxn(usb.serialPort)); // HXN does not use divisor - int minBaudRate = ProlificWrapper.isDeviceTypeT(usb.serialPort) ? 6 : 46; + int minBaudRate = ProlificSerialPortWrapper.isDeviceTypeT(usb.serialPort) ? 6 : 46; try { usb.setParameters(minBaudRate-1, 8, 1, UsbSerialPort.PARITY_NONE); fail("baud rate to low expected"); @@ -478,7 +479,7 @@ public class DeviceTest { } for(int baudRate : new int[] {300, 2400, 19200, 115200} ) { - if(baudRate == 300 && isCp21xxRestrictedPort) { + if(baudRate == 300 && usb.isCp21xxRestrictedPort) { try { usb.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE); fail("baudrate 300 on cp21xx restricted port"); @@ -491,7 +492,7 @@ public class DeviceTest { doReadWrite(baudRate+"/8N1"); } - if(rfc2217_server_nonstandard_baudrates && !isCp21xxRestrictedPort) { + if(rfc2217_server_nonstandard_baudrates && !usb.isCp21xxRestrictedPort) { usb.setParameters(42000, 8, 1, UsbSerialPort.PARITY_NONE); telnet.setParameters(42000, 8, 1, UsbSerialPort.PARITY_NONE); @@ -577,7 +578,7 @@ public class DeviceTest { data = telnet.read(2); assertThat("19000/7N1", data, equalTo(new byte[]{(byte) 0x80, (byte) 0xff})); } catch (UnsupportedOperationException e) { - if(!isCp21xxRestrictedPort) + if(!usb.isCp21xxRestrictedPort) throw e; } try { @@ -588,7 +589,7 @@ public class DeviceTest { data = telnet.read(2); assertThat("19000/6N1", data, equalTo(new byte[]{(byte) 0xc0, (byte) 0xff})); } catch (UnsupportedOperationException e) { - if (!(isCp21xxRestrictedPort || usb.serialDriver instanceof FtdiSerialDriver)) + if (!(usb.isCp21xxRestrictedPort || usb.serialDriver instanceof FtdiSerialDriver)) throw e; } try { @@ -599,7 +600,7 @@ public class DeviceTest { data = telnet.read(2); assertThat("19000/5N1", data, equalTo(new byte[] {(byte)0xe0, (byte)0xff})); } catch (UnsupportedOperationException e) { - if (!(isCp21xxRestrictedPort || usb.serialDriver instanceof FtdiSerialDriver)) + if (!(usb.isCp21xxRestrictedPort || usb.serialDriver instanceof FtdiSerialDriver)) throw e; } } @@ -622,7 +623,7 @@ public class DeviceTest { } catch (IllegalArgumentException ignored) { } } - if(isCp21xxRestrictedPort) { + if(usb.isCp21xxRestrictedPort) { usb.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); usb.setParameters(19200, 8, 1, UsbSerialPort.PARITY_EVEN); usb.setParameters(19200, 8, 1, UsbSerialPort.PARITY_ODD); @@ -752,7 +753,7 @@ public class DeviceTest { data = telnet.read(2); assertThat("19200/8N1", data, equalTo(new byte[]{1, 11})); } catch(UnsupportedOperationException e) { - if(!isCp21xxRestrictedPort) + if(!usb.isCp21xxRestrictedPort) throw e; } try { @@ -790,8 +791,23 @@ public class DeviceTest { } @Test - public void writeTimeout() throws Exception { + public void writeSizes() throws Exception { + assertNull(CommonUsbSerialPortWrapper.getWriteBuffer(usb.serialPort)); + ((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(12); + assertEquals(12, CommonUsbSerialPortWrapper.getWriteBuffer(usb.serialPort).length); + ((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(-1); + ((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(-1); + assertNull(CommonUsbSerialPortWrapper.getWriteBuffer(usb.serialPort)); usb.open(); + ((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(12); + assertEquals(12, CommonUsbSerialPortWrapper.getWriteBuffer(usb.serialPort).length); + ((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(-1); + ((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(-1); + assertEquals(usb.serialPort.getWriteEndpoint().getMaxPacketSize(), + CommonUsbSerialPortWrapper.getWriteBuffer(usb.serialPort).length); + assertEquals(usb.serialPort.getWriteEndpoint().getMaxPacketSize(), + usb.serialPort.getReadEndpoint().getMaxPacketSize()); + int baudRate = 300; if(usb.serialDriver instanceof Cp21xxSerialDriver && usb.serialDriver.getPorts().size() > 1) baudRate = 2400; @@ -815,27 +831,32 @@ public class DeviceTest { int writeBufferSize = writePacketSize * writePackets; Log.d(TAG, "write packet size = " + writePacketSize + ", write buffer size = " + writeBufferSize); - int[] writeSizes = usb.getWriteSizes(); - assertNotNull(writeSizes); - assertEquals("write packet size", writeSizes[0], writePacketSize); - assertTrue("write buffer size", Arrays.binarySearch(writeSizes, writeBufferSize) > 0); - purgeWriteBuffer(purgeTimeout); - if(usb.serialDriver instanceof CdcAcmSerialDriver) - return; // serial processing to slow for tests below, but they anyway only check shared code in CommonUsbSerialPort - if(usb.serialDriver instanceof Cp21xxSerialDriver && usb.serialDriver.getPorts().size() > 1) - return; // write buffer size detection unreliable as baud rate to high + assertEquals("write packet size", usb.writePacketSize, writePacketSize); + if (usb.serialDriver instanceof Cp21xxSerialDriver && usb.serialDriver.getPorts().size() == 1) // write buffer size detection is unreliable + assertTrue("write buffer size " + writeBufferSize, writeBufferSize == usb.writeBufferSize || writeBufferSize == usb.writeBufferSize + 64); + else + assertEquals("write buffer size", usb.writeBufferSize, writeBufferSize); + } + @Test + public void writeTimeout() throws Exception { + // serial processing to slow for tests below, but they anyway only check shared code in CommonUsbSerialPort + Assume.assumeFalse(usb.serialDriver instanceof CdcAcmSerialDriver); + // write buffer size detection unreliable as baud rate to high + Assume.assumeFalse(usb.serialDriver instanceof Cp21xxSerialDriver && usb.serialDriver.getPorts().size() > 1); + + usb.open(); usb.setParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE); telnet.setParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE); TestBuffer tbuf; + int purgeTimeout = 250; // total write timeout - tbuf = new TestBuffer(writeBufferSize + writePacketSize); - int timeout = writePacketSize / 32 * 50; // time for 1.5 packets. write 48 byte in 50 msec at 9600 baud - ((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(writePacketSize); + tbuf = new TestBuffer(usb.writeBufferSize + usb.writePacketSize); + int timeout = usb.writePacketSize / 32 * 50; // time for 1.5 packets. write 48 byte in 50 msec at 9600 baud usb.serialPort.write(tbuf.buf, timeout); purgeWriteBuffer(purgeTimeout); - tbuf = new TestBuffer(writeBufferSize + 2*writePacketSize); + tbuf = new TestBuffer(usb.writeBufferSize + 2*usb.writePacketSize); try { usb.serialPort.write(tbuf.buf, timeout); // would not fail if each block has own timeout fail("write error expected"); @@ -843,12 +864,11 @@ public class DeviceTest { purgeWriteBuffer(purgeTimeout); // infinite wait - ((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(writePacketSize); usb.serialPort.write(tbuf.buf, 0); purgeWriteBuffer(purgeTimeout); // timeout in bulkTransfer + SerialTimeoutException.bytesTransferred - int readWait = writePacketSize > 64 ? 250 : 50; + int readWait = usb.writePacketSize > 64 ? 250 : 50; ((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(tbuf.buf.length); try { usb.serialPort.write(tbuf.buf, timeout); @@ -860,10 +880,10 @@ public class DeviceTest { tbuf.testRead(data); } assertEquals(0, ex.bytesTransferred); - assertEquals(writeBufferSize + writePacketSize, tbuf.len); + assertEquals(usb.writeBufferSize + usb.writePacketSize, tbuf.len); } purgeWriteBuffer(purgeTimeout); - ((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(writePacketSize); + ((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(-1); tbuf.len = 0; try { usb.serialPort.write(tbuf.buf, timeout); @@ -874,8 +894,8 @@ public class DeviceTest { data = telnet.read(-1, readWait)) { tbuf.testRead(data); } - assertEquals(writeBufferSize + writePacketSize, ex.bytesTransferred); - assertEquals(writeBufferSize + writePacketSize, tbuf.len); + assertEquals(usb.writeBufferSize + usb.writePacketSize, ex.bytesTransferred); + assertEquals(usb.writeBufferSize + usb.writePacketSize, tbuf.len); } purgeWriteBuffer(purgeTimeout); @@ -916,15 +936,12 @@ public class DeviceTest { if(usb.serialDriver instanceof Cp21xxSerialDriver && usb.serialDriver.getPorts().size() == 1) purge = false; // purge is blocking - int[] writeSizes = usb.getWriteSizes(); - int writePacketSize = writeSizes[0]; - int writeBufferSize = writeSizes[1]; int purgeTimeout = 250; TestBuffer tbuf; long begin; int duration1, duration2, retries, i; retries = purge ? 10 : 1; - tbuf = new TestBuffer(writeBufferSize); + tbuf = new TestBuffer(usb.writeBufferSize); ((CommonUsbSerialPort) usb.serialPort).setWriteBufferSize(tbuf.buf.length); Log.d(TAG, "writeDuration: full write begin"); @@ -938,7 +955,7 @@ public class DeviceTest { if(!purge) purgeWriteBuffer(purgeTimeout); Log.d(TAG, "writeDuration: full write end, duration " + duration1/(float)(retries) + " msec"); - ((CommonUsbSerialPort) usb.serialPort).setWriteBufferSize(writePacketSize); + ((CommonUsbSerialPort) usb.serialPort).setWriteBufferSize(-1); Log.d(TAG, "writeDuration: packet write begin"); begin = System.currentTimeMillis(); for(i=0; i 1) { assertThat(usb.read(1), equalTo("y".getBytes())); // cp2105/0 @@ -1675,40 +1692,15 @@ public class DeviceTest { byte[] data; int sleep = 10; - // output lines are supported by all drivers - // input lines are supported by all drivers except CDC - boolean inputLinesSupported = false; - boolean inputLinesConnected = false; - boolean onlyRtsCts = false; - if (usb.serialDriver instanceof FtdiSerialDriver) { - inputLinesSupported = true; - if(usb.serialDriver.getDevice().getProductId() == UsbId.FTDI_FT2232H) - inputLinesConnected = true; // I only have 74LS138 connected at FT2232, not at FT232 - if(usb.serialDriver.getDevice().getProductId() == UsbId.FTDI_FT231X) { - inputLinesConnected = true; - onlyRtsCts = true; // I only test with FT230X that has only these 2 control lines. DTR is silently ignored - } - } else if (usb.serialDriver instanceof Cp21xxSerialDriver) { - inputLinesSupported = true; - if(usb.serialDriver.getPorts().size() == 1) - inputLinesConnected = true; // I only have 74LS138 connected at CP2102, not at CP2105 - } else if (usb.serialDriver instanceof ProlificSerialDriver) { - inputLinesSupported = true; - inputLinesConnected = true; - } else if (usb.serialDriver instanceof Ch34xSerialDriver) { - inputLinesSupported = true; - if(usb.serialDriver.getDevice().getProductId() == UsbId.QINHENG_CH340) - inputLinesConnected = true; // I only have 74LS138 connected at CH230, not connected at CH341A - } - Boolean inputLineFalse = inputLinesSupported ? Boolean.FALSE : null; - Boolean inputLineTrue = inputLinesConnected ? Boolean.TRUE : inputLineFalse; + Boolean inputLineFalse = usb.inputLinesSupported ? Boolean.FALSE : null; + Boolean inputLineTrue = usb.inputLinesConnected ? Boolean.TRUE : inputLineFalse; - EnumSet supportedControlLines = EnumSet.of(UsbSerialPort.ControlLine.RTS, UsbSerialPort.ControlLine.DTR); - if(inputLinesSupported) { - supportedControlLines.add(UsbSerialPort.ControlLine.CTS); - supportedControlLines.add(UsbSerialPort.ControlLine.DSR); - supportedControlLines.add(UsbSerialPort.ControlLine.CD); - supportedControlLines.add(UsbSerialPort.ControlLine.RI); + EnumSet supportedControlLines = EnumSet.of(ControlLine.RTS, ControlLine.DTR); + if(usb.inputLinesSupported) { + supportedControlLines.add(ControlLine.CTS); + supportedControlLines.add(ControlLine.DSR); + supportedControlLines.add(ControlLine.CD); + supportedControlLines.add(ControlLine.RI); } // UsbSerialProber creates new UsbSerialPort objects which resets control lines, @@ -1723,16 +1715,16 @@ public class DeviceTest { // control lines reset on initial open data = "none".getBytes(); - assertEquals(inputLinesConnected && !onlyRtsCts - ? EnumSet.of(UsbSerialPort.ControlLine.RI) - : EnumSet.noneOf(UsbSerialPort.ControlLine.class), + assertEquals(usb.inputLinesConnected && !usb.inputLinesOnlyRtsCts + ? EnumSet.of(ControlLine.RI) + : EnumSet.noneOf(ControlLine.class), usb.serialPort.getControlLines()); assertThat(usb.getControlLine(usb.serialPort::getRTS), equalTo(Boolean.FALSE)); assertThat(usb.getControlLine(usb.serialPort::getCTS), equalTo(inputLineFalse)); assertThat(usb.getControlLine(usb.serialPort::getDTR), equalTo(Boolean.FALSE)); assertThat(usb.getControlLine(usb.serialPort::getDSR), equalTo(inputLineFalse)); assertThat(usb.getControlLine(usb.serialPort::getCD), equalTo(inputLineFalse)); - assertThat(usb.getControlLine(usb.serialPort::getRI), equalTo(onlyRtsCts ? Boolean.FALSE : inputLineTrue)); + assertThat(usb.getControlLine(usb.serialPort::getRI), equalTo(usb.inputLinesOnlyRtsCts ? Boolean.FALSE : inputLineTrue)); telnet.write(data); if(usb.serialDriver instanceof CdcAcmSerialDriver) // arduino: control line feedback as serial_state notification is not implemented. @@ -1746,9 +1738,9 @@ public class DeviceTest { data = "rts ".getBytes(); usb.serialPort.setRTS(true); Thread.sleep(sleep); - assertEquals(inputLinesConnected - ? EnumSet.of(UsbSerialPort.ControlLine.RTS, UsbSerialPort.ControlLine.CTS) - : EnumSet.of(UsbSerialPort.ControlLine.RTS), + assertEquals(usb.inputLinesConnected + ? EnumSet.of(ControlLine.RTS, ControlLine.CTS) + : EnumSet.of(ControlLine.RTS), usb.serialPort.getControlLines()); assertThat(usb.getControlLine(usb.serialPort::getRTS), equalTo(Boolean.TRUE)); assertThat(usb.getControlLine(usb.serialPort::getCTS), equalTo(inputLineTrue)); @@ -1764,17 +1756,17 @@ public class DeviceTest { data = "both".getBytes(); usb.serialPort.setDTR(true); Thread.sleep(sleep); - assertEquals(onlyRtsCts - ? EnumSet.of(UsbSerialPort.ControlLine.RTS, UsbSerialPort.ControlLine.DTR, UsbSerialPort.ControlLine.CTS) - : inputLinesConnected - ? EnumSet.of(UsbSerialPort.ControlLine.RTS, UsbSerialPort.ControlLine.DTR, UsbSerialPort.ControlLine.CD) - : EnumSet.of(UsbSerialPort.ControlLine.RTS, UsbSerialPort.ControlLine.DTR), + assertEquals(usb.inputLinesOnlyRtsCts + ? EnumSet.of(ControlLine.RTS, ControlLine.DTR, ControlLine.CTS) + : usb.inputLinesConnected + ? EnumSet.of(ControlLine.RTS, ControlLine.DTR, ControlLine.CD) + : EnumSet.of(ControlLine.RTS, ControlLine.DTR), usb.serialPort.getControlLines()); assertThat(usb.getControlLine(usb.serialPort::getRTS), equalTo(Boolean.TRUE)); - assertThat(usb.getControlLine(usb.serialPort::getCTS), equalTo(onlyRtsCts ? Boolean.TRUE : inputLineFalse)); + assertThat(usb.getControlLine(usb.serialPort::getCTS), equalTo(usb.inputLinesOnlyRtsCts ? Boolean.TRUE : inputLineFalse)); assertThat(usb.getControlLine(usb.serialPort::getDTR), equalTo(Boolean.TRUE)); assertThat(usb.getControlLine(usb.serialPort::getDSR), equalTo(inputLineFalse)); - assertThat(usb.getControlLine(usb.serialPort::getCD), equalTo(onlyRtsCts ? Boolean.FALSE : inputLineTrue)); + assertThat(usb.getControlLine(usb.serialPort::getCD), equalTo(usb.inputLinesOnlyRtsCts ? Boolean.FALSE : inputLineTrue)); assertThat(usb.getControlLine(usb.serialPort::getRI), equalTo(inputLineFalse)); telnet.write(data); assertThat(Arrays.toString(data), usb.read(4), equalTo(data)); @@ -1784,14 +1776,14 @@ public class DeviceTest { data = "dtr ".getBytes(); usb.serialPort.setRTS(false); Thread.sleep(sleep); - assertEquals(inputLinesConnected && !onlyRtsCts - ? EnumSet.of(UsbSerialPort.ControlLine.DTR, UsbSerialPort.ControlLine.DSR) - : EnumSet.of(UsbSerialPort.ControlLine.DTR), + assertEquals(usb.inputLinesConnected && !usb.inputLinesOnlyRtsCts + ? EnumSet.of(ControlLine.DTR, ControlLine.DSR) + : EnumSet.of(ControlLine.DTR), usb.serialPort.getControlLines()); assertThat(usb.getControlLine(usb.serialPort::getRTS), equalTo(Boolean.FALSE)); assertThat(usb.getControlLine(usb.serialPort::getCTS), equalTo(inputLineFalse)); assertThat(usb.getControlLine(usb.serialPort::getDTR), equalTo(Boolean.TRUE)); - assertThat(usb.getControlLine(usb.serialPort::getDSR), equalTo(onlyRtsCts ? Boolean.FALSE : inputLineTrue)); + assertThat(usb.getControlLine(usb.serialPort::getDSR), equalTo(usb.inputLinesOnlyRtsCts ? Boolean.FALSE : inputLineTrue)); assertThat(usb.getControlLine(usb.serialPort::getCD), equalTo(inputLineFalse)); assertThat(usb.getControlLine(usb.serialPort::getRI), equalTo(inputLineFalse)); telnet.write(data); @@ -1800,7 +1792,7 @@ public class DeviceTest { assertThat(Arrays.toString(data), telnet.read(4), equalTo(data)); // control lines retained over close+open - boolean inputRetained = inputLinesConnected; + boolean inputRetained = usb.inputLinesConnected; boolean outputRetained = true; usb.serialPort.setRTS(true); usb.serialPort.setDTR(false); @@ -1808,9 +1800,9 @@ public class DeviceTest { usb.open(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_CONTROL_LINE_INIT, UsbWrapper.OpenCloseFlags.NO_IOMANAGER_THREAD)); usb.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); - EnumSet retainedControlLines = EnumSet.noneOf(UsbSerialPort.ControlLine.class); - if(outputRetained) retainedControlLines.add(UsbSerialPort.ControlLine.RTS); - if(inputRetained) retainedControlLines.add(UsbSerialPort.ControlLine.CTS); + EnumSet retainedControlLines = EnumSet.noneOf(ControlLine.class); + if(outputRetained) retainedControlLines.add(ControlLine.RTS); + if(inputRetained) retainedControlLines.add(ControlLine.CTS); assertEquals(retainedControlLines, usb.serialPort.getControlLines()); assertThat(usb.getControlLine(usb.serialPort::getRTS), equalTo(outputRetained)); assertThat(usb.getControlLine(usb.serialPort::getCTS), equalTo(inputRetained ? inputLineTrue : inputLineFalse)); @@ -1824,25 +1816,25 @@ public class DeviceTest { usb.serialPort.setDTR(false); usb.close(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_CONTROL_LINE_INIT)); usb.open(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_CONTROL_LINE_INIT, UsbWrapper.OpenCloseFlags.NO_IOMANAGER_THREAD)); - assertEquals(EnumSet.of(UsbSerialPort.ControlLine.RI), usb.serialPort.getControlLines()); + assertEquals(EnumSet.of(ControlLine.RI), usb.serialPort.getControlLines()); usb.serialPort.setRTS(true); usb.serialPort.setDTR(false); usb.close(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_CONTROL_LINE_INIT)); usb.open(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_CONTROL_LINE_INIT, UsbWrapper.OpenCloseFlags.NO_IOMANAGER_THREAD)); - assertEquals(EnumSet.of(UsbSerialPort.ControlLine.RTS, UsbSerialPort.ControlLine.CTS), usb.serialPort.getControlLines()); + assertEquals(EnumSet.of(ControlLine.RTS, ControlLine.CTS), usb.serialPort.getControlLines()); usb.serialPort.setRTS(false); usb.serialPort.setDTR(true); usb.close(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_CONTROL_LINE_INIT)); usb.open(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_CONTROL_LINE_INIT, UsbWrapper.OpenCloseFlags.NO_IOMANAGER_THREAD)); - assertEquals(EnumSet.of(UsbSerialPort.ControlLine.DTR, UsbSerialPort.ControlLine.DSR), usb.serialPort.getControlLines()); + assertEquals(EnumSet.of(ControlLine.DTR, ControlLine.DSR), usb.serialPort.getControlLines()); usb.serialPort.setRTS(true); usb.serialPort.setDTR(true); usb.close(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_CONTROL_LINE_INIT)); usb.open(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_CONTROL_LINE_INIT, UsbWrapper.OpenCloseFlags.NO_IOMANAGER_THREAD)); - assertEquals(EnumSet.of(UsbSerialPort.ControlLine.RTS, UsbSerialPort.ControlLine.DTR, UsbSerialPort.ControlLine.CD), usb.serialPort.getControlLines()); + assertEquals(EnumSet.of(ControlLine.RTS, ControlLine.DTR, ControlLine.CD), usb.serialPort.getControlLines()); } // force error @@ -1893,7 +1885,7 @@ public class DeviceTest { if (usb.serialDriver instanceof CdcAcmSerialDriver) { // BREAK forwarding not implemented by arduino_leonardo_bridge.ino assertThat("", data, equalTo(new byte[]{})); - } else if(isCp21xxRestrictedPort) { + } else if(usb.isCp21xxRestrictedPort) { assertThat("", data, equalTo(new byte[]{0x26})); // send the last byte again? } else { assertThat("", data, equalTo(new byte[]{0})); @@ -1979,7 +1971,7 @@ public class DeviceTest { fail("setBreak error expected"); } catch (IOException ignored) { } - usb.close(); + usb.close(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_DEVICE_CONNECTION)); try { usb.open(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_IOMANAGER_THREAD, UsbWrapper.OpenCloseFlags.NO_DEVICE_CONNECTION)); fail("open error expected"); @@ -2009,8 +2001,6 @@ public class DeviceTest { usb.open(); assertTrue(usb.serialPort.isOpen()); - assertEquals(usb.serialPort.getWriteEndpoint().getMaxPacketSize(), - usb.serialPort.getReadEndpoint().getMaxPacketSize()); s = usb.serialPort.getSerial(); // with target sdk 29 can throw SecurityException before USB permission dialog is confirmed // not all devices implement serial numbers. some observed values are: @@ -2059,7 +2049,7 @@ public class DeviceTest { long t3 = System.currentTimeMillis(); ftdiSerialPort.setLatencyTimer(lt); assertTrue("latency 1: expected < 100, got "+ (t2-t1), (t2-t1) < 100); - assertTrue("latency 100: expected > 100, got " + (t3-t2), (t3-t2) > 100); + assertTrue("latency 100: expected >= 100, got " + (t3-t2), (t3-t2) >= 100); usb.deviceConnection.close(); try { diff --git a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/driver/CommonUsbSerialPortWrapper.java b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/driver/CommonUsbSerialPortWrapper.java new file mode 100644 index 0000000..1d87e70 --- /dev/null +++ b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/driver/CommonUsbSerialPortWrapper.java @@ -0,0 +1,8 @@ +package com.hoho.android.usbserial.driver; + +public class CommonUsbSerialPortWrapper { + public static byte[] getWriteBuffer(UsbSerialPort serialPort) { + CommonUsbSerialPort commonSerialPort = (CommonUsbSerialPort) serialPort; + return commonSerialPort.mWriteBuffer; + } +} diff --git a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/driver/ProlificWrapper.java b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/driver/ProlificSerialPortWrapper.java similarity index 93% rename from usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/driver/ProlificWrapper.java rename to usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/driver/ProlificSerialPortWrapper.java index fa7abd6..ca2dfbb 100644 --- a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/driver/ProlificWrapper.java +++ b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/driver/ProlificSerialPortWrapper.java @@ -1,6 +1,6 @@ package com.hoho.android.usbserial.driver; -public class ProlificWrapper { +public class ProlificSerialPortWrapper { public static boolean isDeviceTypeT(UsbSerialPort serialPort) { ProlificSerialDriver.ProlificSerialPort prolificSerialPort = (ProlificSerialDriver.ProlificSerialPort) serialPort; return prolificSerialPort.mDeviceType == ProlificSerialDriver.DeviceType.DEVICE_TYPE_T; diff --git a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/util/UsbWrapper.java b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/util/UsbWrapper.java index 3eab1ec..189a242 100644 --- a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/util/UsbWrapper.java +++ b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/util/UsbWrapper.java @@ -17,6 +17,7 @@ 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.ProlificSerialDriver; +import com.hoho.android.usbserial.driver.UsbId; import com.hoho.android.usbserial.driver.UsbSerialDriver; import com.hoho.android.usbserial.driver.UsbSerialPort; @@ -52,6 +53,13 @@ public class UsbWrapper implements SerialInputOutputManager.Listener { public boolean readBlock = false; long readTime = 0; + // device properties + public boolean isCp21xxRestrictedPort; // second port of Cp2105 has limited dataBits, stopBits, parity + public boolean inputLinesSupported; + public boolean inputLinesConnected; + public boolean inputLinesOnlyRtsCts; + public int writePacketSize = -1; + public int writeBufferSize = -1; public UsbWrapper(Context context, UsbSerialDriver serialDriver, int devicePort) { this.context = context; @@ -86,6 +94,50 @@ public class UsbWrapper implements SerialInputOutputManager.Listener { Log.d(TAG,"USB permission "+granted[0]); assertTrue("USB permission dialog not confirmed", granted[0]==null?false:granted[0]); } + + // extract some device properties: + isCp21xxRestrictedPort = serialDriver instanceof Cp21xxSerialDriver && serialDriver.getPorts().size()==2 && serialPort.getPortNumber() == 1; + // output lines are supported by all drivers + // input lines are supported by all drivers except CDC + if (serialDriver instanceof FtdiSerialDriver) { + inputLinesSupported = true; + if(serialDriver.getDevice().getProductId() == UsbId.FTDI_FT2232H) + inputLinesConnected = true; // I only have 74LS138 connected at FT2232, not at FT232 + if(serialDriver.getDevice().getProductId() == UsbId.FTDI_FT231X) { + inputLinesConnected = true; + inputLinesOnlyRtsCts = true; // I only test with FT230X that has only these 2 control lines. DTR is silently ignored + } + } else if (serialDriver instanceof Cp21xxSerialDriver) { + inputLinesSupported = true; + if(serialDriver.getPorts().size() == 1) + inputLinesConnected = true; // I only have 74LS138 connected at CP2102, not at CP2105 + } else if (serialDriver instanceof ProlificSerialDriver) { + inputLinesSupported = true; + inputLinesConnected = true; + } else if (serialDriver instanceof Ch34xSerialDriver) { + inputLinesSupported = true; + if(serialDriver.getDevice().getProductId() == UsbId.QINHENG_CH340) + inputLinesConnected = true; // I only have 74LS138 connected at CH340, not connected at CH341A + } + + if (serialDriver instanceof Cp21xxSerialDriver) { + if (serialDriver.getPorts().size() == 1) { writePacketSize = 64; writeBufferSize = 576; } + else if (serialPort.getPortNumber() == 0) { writePacketSize = 64; writeBufferSize = 320; } + else { writePacketSize = 32; writeBufferSize = 128; }; //, 160}; // write buffer size detection is unreliable + } else if (serialDriver instanceof Ch34xSerialDriver) { + writePacketSize = 32; writeBufferSize = 64; + } else if (serialDriver instanceof ProlificSerialDriver) { + writePacketSize = 64; writeBufferSize = 256; + } else if (serialDriver instanceof FtdiSerialDriver) { + switch (serialDriver.getPorts().size()) { + case 1: writePacketSize = 64; writeBufferSize = 128; break; + case 2: writePacketSize = 512; writeBufferSize = 4096; break; + case 4: writePacketSize = 512; writeBufferSize = 2048; break; + } + } else if (serialDriver instanceof CdcAcmSerialDriver) { + writePacketSize = 64; writeBufferSize = 128; + } + } public void tearDown() { 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 fba4966..991a637 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 @@ -28,7 +28,6 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort { public static boolean DEBUG = false; private static final String TAG = CommonUsbSerialPort.class.getSimpleName(); - private static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024; private static final int MAX_READ_SIZE = 16 * 1024; // = old bulkTransfer limit protected final UsbDevice mDevice; @@ -40,15 +39,18 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort { protected UsbEndpoint mWriteEndpoint; protected UsbRequest mUsbRequest; - protected final Object mWriteBufferLock = new Object(); - /** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */ + /** + * Internal write buffer. + * Guarded by {@link #mWriteBufferLock}. + * Default length = mReadEndpoint.getMaxPacketSize() + **/ protected byte[] mWriteBuffer; + protected final Object mWriteBufferLock = new Object(); + public CommonUsbSerialPort(UsbDevice device, int portNumber) { mDevice = device; mPortNumber = portNumber; - - mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE]; } @Override @@ -87,11 +89,19 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort { * Sets the size of the internal buffer used to exchange data with the USB * stack for write operations. Most users should not need to change this. * - * @param bufferSize the size in bytes + * @param bufferSize the size in bytes, <= 0 resets original size */ public final void setWriteBufferSize(int bufferSize) { synchronized (mWriteBufferLock) { - if (bufferSize == mWriteBuffer.length) { + if (bufferSize <= 0) { + if (mWriteEndpoint != null) { + bufferSize = mWriteEndpoint.getMaxPacketSize(); + } else { + mWriteBuffer = null; + return; + } + } + if (mWriteBuffer != null && bufferSize == mWriteBuffer.length) { return; } mWriteBuffer = new byte[bufferSize]; @@ -219,6 +229,9 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort { synchronized (mWriteBufferLock) { final byte[] writeBuffer; + if (mWriteBuffer == null) { + mWriteBuffer = new byte[mWriteEndpoint.getMaxPacketSize()]; + } requestLength = Math.min(src.length - offset, mWriteBuffer.length); if (offset == 0) { writeBuffer = src;