From cffe54e15c65a633f644b848f1476ee309ec4d0f Mon Sep 17 00:00:00 2001 From: kai-morich Date: Fri, 20 Mar 2020 20:11:47 +0100 Subject: [PATCH] test control lines --- usbSerialForAndroid/coverage.gradle | 6 + .../hoho/android/usbserial/DeviceTest.java | 220 +++++++++++++++--- 2 files changed, 198 insertions(+), 28 deletions(-) diff --git a/usbSerialForAndroid/coverage.gradle b/usbSerialForAndroid/coverage.gradle index f5c6fa4..2d08c63 100644 --- a/usbSerialForAndroid/coverage.gradle +++ b/usbSerialForAndroid/coverage.gradle @@ -43,3 +43,9 @@ android { } } } +// create report even if tests fail +project.gradle.taskGraph.whenReady { + -> project.tasks.findAll { it.name =~ /connected.+AndroidTest/ }.each { + it.ignoreFailures = true + } +} 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 d7d166b..931d691 100644 --- a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java +++ b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java @@ -54,13 +54,16 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; +import java.util.Arrays; import java.util.Deque; +import java.util.EnumSet; import java.util.LinkedList; import java.util.List; import java.util.concurrent.Executors; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -108,6 +111,8 @@ public class DeviceTest implements SerialInputOutputManager.Listener { private int telnetWriteDelay = 0; private boolean isCp21xxRestrictedPort = false; // second port of Cp2105 has limited dataBits, stopBits, parity + enum UsbOpenFlags { NO_IOMANAGER_THREAD, NO_CONTROL_LINE_INIT }; + @Rule public TestRule watcher = new TestWatcher() { protected void starting(Description description) { @@ -292,14 +297,20 @@ public class DeviceTest implements SerialInputOutputManager.Listener { } private void usbClose() { + usbClose(EnumSet.noneOf(UsbOpenFlags.class)); + } + + private void usbClose(EnumSet flags) { if (usbIoManager != null) { usbIoManager.setListener(null); usbIoManager.stop(); } if (usbSerialPort != null) { try { - usbSerialPort.setDTR(false); - usbSerialPort.setRTS(false); + if(!flags.contains(UsbOpenFlags.NO_CONTROL_LINE_INIT)) { + usbSerialPort.setDTR(false); + usbSerialPort.setRTS(false); + } } catch (Exception ignored) { } try { @@ -323,17 +334,23 @@ public class DeviceTest implements SerialInputOutputManager.Listener { } } - private void usbOpen(boolean withIoManager) throws Exception { - usbOpen(withIoManager, 0); + private void usbOpen() throws Exception { + usbOpen(EnumSet.noneOf(UsbOpenFlags.class), 0); } - private void usbOpen(boolean withIoManager, int ioManagerTimout) throws Exception { + private void usbOpen(EnumSet flags) throws Exception { + usbOpen(flags, 0); + } + + private void usbOpen(EnumSet flags, int ioManagerTimeout) throws Exception { usbDeviceConnection = usbManager.openDevice(usbSerialDriver.getDevice()); usbSerialPort = usbSerialDriver.getPorts().get(test_device_port); usbSerialPort.open(usbDeviceConnection); - usbSerialPort.setDTR(true); - usbSerialPort.setRTS(true); - if(withIoManager) { + if(!flags.contains(UsbOpenFlags.NO_CONTROL_LINE_INIT)) { + usbSerialPort.setDTR(true); + usbSerialPort.setRTS(true); + } + if(!flags.contains(UsbOpenFlags.NO_IOMANAGER_THREAD)) { usbIoManager = new SerialInputOutputManager(usbSerialPort, this) { @Override public void run() { @@ -342,8 +359,8 @@ public class DeviceTest implements SerialInputOutputManager.Listener { super.run(); } }; - usbIoManager.setReadTimeout(ioManagerTimout); - usbIoManager.setWriteTimeout(ioManagerTimout); + usbIoManager.setReadTimeout(ioManagerTimeout); + usbIoManager.setWriteTimeout(ioManagerTimeout); Executors.newSingleThreadExecutor().submit(usbIoManager); } synchronized (usbReadBuffer) { @@ -525,7 +542,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { @Test public void openClose() throws Exception { - usbOpen(true); + usbOpen(); telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); doReadWrite(""); @@ -562,7 +579,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { } usbSerialPort = null; - usbOpen(true); + usbOpen(); telnetParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE); usbParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE); doReadWrite(""); @@ -583,7 +600,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { @Test public void baudRate() throws Exception { - usbOpen(true); + usbOpen(); if (false) { // default baud rate // CP2102: only works if first connection after attaching device @@ -698,7 +715,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { public void dataBits() throws Exception { byte[] data; - usbOpen(true); + usbOpen(); for(int i: new int[] {0, 4, 9}) { try { usbParameters(19200, i, 1, UsbSerialPort.PARITY_NONE); @@ -777,7 +794,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { byte[] _7s1 = {(byte)0x00, (byte)0x01, (byte)0x7e, (byte)0x7f}; byte[] data; - usbOpen(true); + usbOpen(); for(int i: new int[] {-1, 5}) { try { usbParameters(19200, 8, 1, i); @@ -874,7 +891,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { public void stopBits() throws Exception { byte[] data; - usbOpen(true); + usbOpen(); for (int i : new int[]{0, 4}) { try { usbParameters(19200, 8, i, UsbSerialPort.PARITY_NONE); @@ -952,7 +969,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { @Test public void writeTimeout() throws Exception { - usbOpen(true); + usbOpen(); usbParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); @@ -1016,7 +1033,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { @Test public void writeFragments() throws Exception { - usbOpen(true); + usbOpen(); usbParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); @@ -1033,7 +1050,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); + usbOpen(); usbParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); @@ -1108,7 +1125,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { if(usbSerialDriver instanceof CdcAcmSerialDriver) writeAhead = 50; - usbOpen(true, readTimeout); + usbOpen(EnumSet.noneOf(UsbOpenFlags.class), readTimeout); usbParameters(baudrate, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(baudrate, 8, 1, UsbSerialPort.PARITY_NONE); @@ -1157,7 +1174,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); + usbOpen(); usbParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); boolean longlines = !(usbSerialDriver instanceof CdcAcmSerialDriver); @@ -1208,7 +1225,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { public void purgeHwBuffers() throws Exception { // purge write buffer // 2400 is slowest baud rate for isCp21xxRestrictedPort - usbOpen(true); + usbOpen(); usbParameters(2400, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(2400, 8, 1, UsbSerialPort.PARITY_NONE); byte[] buf = new byte[64]; @@ -1232,7 +1249,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { // purge read buffer usbClose(); - usbOpen(false); + usbOpen(EnumSet.of(UsbOpenFlags.NO_IOMANAGER_THREAD)); usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); telnetWrite("x".getBytes()); @@ -1279,7 +1296,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { assertEquals(200, usbIoManager.getWriteTimeout()); // w/o timeout: write delayed until something is read - usbOpen(true); + usbOpen(); usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); usbIoManager.writeAsync(buf); @@ -1298,7 +1315,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { usbClose(); // with timeout: write after timeout - usbOpen(true, 100); + usbOpen(EnumSet.noneOf(UsbOpenFlags.class), 100); usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); usbIoManager.writeAsync(buf); @@ -1327,7 +1344,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { } }; - usbOpen(false); + usbOpen(EnumSet.of(UsbOpenFlags.NO_IOMANAGER_THREAD)); usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); @@ -1354,7 +1371,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { assertTrue("not closed in time", closed[0]); // with timeout - usbOpen(false); + usbOpen(EnumSet.of(UsbOpenFlags.NO_IOMANAGER_THREAD)); usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); @@ -1506,9 +1523,156 @@ public class DeviceTest implements SerialInputOutputManager.Listener { } } // test that device recovers from wrong commands - usbOpen(true); + usbOpen(); telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); doReadWrite(""); } + + @Test + /* test not done by RFC2217 server. Instead output control lines are connected to + input control lines with a binary decoder 74LS138, 74LS139, 74HC... or ... + in + A0 = RTS + A1 = DTR + out + Y0 = CD + Y1 = DTS/DSR + Y2 = CTS + Y3 = RI + expected result: + none -> RI + RTS -> CTS + DTR -> DTS/DSR + both -> CD + */ + public void controlLines() throws Exception { + byte[] data; + int sleep = 10; + + // output lines are supported by all drivers + boolean inputLinesSupported = false; + boolean inputLinesConnected = false; + if (usbSerialDriver instanceof FtdiSerialDriver) { + inputLinesSupported = true; + inputLinesConnected = usbSerialDriver.getPorts().size()==2; // I only have 74LS138 connected at FT2232 + } else if (usbSerialDriver instanceof ProlificSerialDriver) { + inputLinesSupported = true; + inputLinesConnected = true; + } + + usbOpen(EnumSet.of(UsbOpenFlags.NO_CONTROL_LINE_INIT)); + usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); + telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); + Thread.sleep(sleep); + + if(usbSerialDriver instanceof ProlificSerialDriver) { + // the initial status is sometimes not available or wrong. + // this is more likely if other tests have been executed before. + // start thread and wait until status hopefully updated. + usbSerialPort.getRI(); // todo + Thread.sleep(sleep); + assertTrue(usbSerialPort.getRI()); + } + data = "none".getBytes(); + assertFalse(usbSerialPort.getRTS()); + assertFalse(usbSerialPort.getCTS()); + assertFalse(usbSerialPort.getDTR()); + assertFalse(usbSerialPort.getDSR()); + assertFalse(usbSerialPort.getCD()); + assertEquals(usbSerialPort.getRI(), inputLinesConnected); + telnetWrite(data); + if(usbSerialDriver instanceof CdcAcmSerialDriver) + // arduino: control line feedback as serial_state notification is not implemented. + // It does not send w/o RTS or DTR, so these control lines can be partly checked here. + assertEquals(0, usbRead().length); + else + assertThat(Arrays.toString(data), usbRead(4), equalTo(data)); + usbWrite(data); + assertThat(Arrays.toString(data), telnetRead(4), equalTo(data)); + + data = "rts ".getBytes(); + usbSerialPort.setRTS(true); + Thread.sleep(sleep); + assertTrue(usbSerialPort.getRTS()); + assertEquals(usbSerialPort.getCTS(), inputLinesConnected); + assertFalse(usbSerialPort.getDTR()); + assertFalse(usbSerialPort.getDSR()); + assertFalse(usbSerialPort.getCD()); + assertFalse(usbSerialPort.getRI()); + telnetWrite(data); + assertThat(Arrays.toString(data), usbRead(4), equalTo(data)); + usbWrite(data); + assertThat(Arrays.toString(data), telnetRead(4), equalTo(data)); + + data = "both".getBytes(); + usbSerialPort.setDTR(true); + Thread.sleep(sleep); + assertTrue(usbSerialPort.getRTS()); + assertFalse(usbSerialPort.getCTS()); + assertTrue(usbSerialPort.getDTR()); + assertFalse(usbSerialPort.getDSR()); + assertEquals(usbSerialPort.getCD(), inputLinesConnected); + assertFalse(usbSerialPort.getRI()); + telnetWrite(data); + assertThat(Arrays.toString(data), usbRead(4), equalTo(data)); + usbWrite(data); + assertThat(Arrays.toString(data), telnetRead(4), equalTo(data)); + + data = "dtr ".getBytes(); + usbSerialPort.setRTS(false); + Thread.sleep(sleep); + assertFalse(usbSerialPort.getRTS()); + assertFalse(usbSerialPort.getCTS()); + assertTrue(usbSerialPort.getDTR()); + assertEquals(usbSerialPort.getDSR(), inputLinesConnected); + assertFalse(usbSerialPort.getCD()); + assertFalse(usbSerialPort.getRI()); + telnetWrite(data); + assertThat(Arrays.toString(data), usbRead(4), equalTo(data)); + usbWrite(data); + assertThat(Arrays.toString(data), telnetRead(4), equalTo(data)); + + // state retained over close/open + boolean inputRetained = inputLinesConnected; + boolean outputRetained = true; + if(usbSerialDriver instanceof FtdiSerialDriver) + outputRetained = false; // todo + usbClose(EnumSet.of(UsbOpenFlags.NO_CONTROL_LINE_INIT)); + usbOpen(EnumSet.of(UsbOpenFlags.NO_CONTROL_LINE_INIT, UsbOpenFlags.NO_IOMANAGER_THREAD)); + usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); + + assertFalse(usbSerialPort.getRTS()); + assertFalse(usbSerialPort.getCTS()); + assertEquals(usbSerialPort.getDTR(), outputRetained); + assertEquals(usbSerialPort.getDSR(), inputRetained); + assertFalse(usbSerialPort.getCD()); + assertFalse(usbSerialPort.getRI()); + + usbClose(EnumSet.of(UsbOpenFlags.NO_CONTROL_LINE_INIT)); + usbOpen(EnumSet.of(UsbOpenFlags.NO_CONTROL_LINE_INIT, UsbOpenFlags.NO_IOMANAGER_THREAD)); + usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); + for (int i = 0; i < usbSerialDriver.getDevice().getInterfaceCount(); i++) + usbDeviceConnection.releaseInterface(usbSerialDriver.getDevice().getInterface(i)); + usbDeviceConnection.close(); + + // set... error + try { + usbSerialPort.setRTS(true); + fail("error expected"); + } catch (IOException ignored) { + } + + // get... error + try { + usbSerialPort.getRI(); + if (!inputLinesSupported) + ; + else if (usbSerialDriver instanceof ProlificSerialDriver) + ; // todo: currently not possible to detect, as bulkTransfer in background thread does not distinguish timeout and error + else + fail("error expected"); + } catch (IOException ignored) { + } + } }