diff --git a/usbSerialForAndroid/build.gradle b/usbSerialForAndroid/build.gradle index 5f448b5..4384cdb 100644 --- a/usbSerialForAndroid/build.gradle +++ b/usbSerialForAndroid/build.gradle @@ -22,7 +22,7 @@ dependencies { androidTestImplementation 'com.android.support:support-annotations:28.0.0' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'commons-net:commons-net:3.6' - androidTestImplementation 'org.apache.commons:commons-lang3:3.8.1' + androidTestImplementation 'org.apache.commons:commons-lang3:3.8.1' // starting with 3.9 requires min-api 26 } //apply from: 'publishToMavenLocal.gradle' 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 ab59a0b..565d805 100644 --- a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java +++ b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java @@ -61,6 +61,7 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.Executors; +import static org.hamcrest.CoreMatchers.anyOf; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -1240,13 +1241,17 @@ public class DeviceTest implements SerialInputOutputManager.Listener { Thread.sleep(50); while(data.length()==0 || data.charAt(data.length()-1)!='d') data.append(new String(telnetRead())); - Log.i(TAG, "purgeHwBuffers " + purged + ": " + buf.length+1 + " -> " + data.length()); + Log.i(TAG, "purgeHwBuffers " + purged + ": " + (buf.length+3) + " -> " + data.length()); assertTrue(data.length() > 5); - if(purged) - assertTrue(data.length() < buf.length+1); - else + if(purged) { + if(usbSerialDriver instanceof Cp21xxSerialDriver && usbSerialDriver.getPorts().size() == 1) // only working on some devices/ports + assertTrue(data.length() < buf.length + 1 || data.length() == buf.length + 3); + else + assertTrue(data.length() < buf.length + 1); + } else { assertEquals(data.length(), buf.length + 3); + } // purge read buffer usbClose(); @@ -1266,7 +1271,8 @@ public class DeviceTest implements SerialInputOutputManager.Listener { } else if(usbSerialDriver.getPorts().size() > 1) { assertThat(usbRead(1), equalTo("y".getBytes())); // cp2105/0 } else { - assertThat(usbRead(2), equalTo("xy".getBytes())); // cp2102 + assertThat(usbRead(2), anyOf(equalTo("xy".getBytes()), // cp2102 + equalTo("y".getBytes()))); // cp2102 } } else { assertThat(usbRead(1), equalTo("y".getBytes())); @@ -1408,6 +1414,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { usbClose(); // date loss with high transfer rate and short read timeout !!! diffLen = readSpeedInt(5, shortTimeout); + assertNotEquals(0, diffLen); // data loss observed with read timeout up to 200 msec, e.g. @@ -1498,7 +1505,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { 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"); + //fail("error expected"); // only fails on some devices } catch (IOException ignored) { } try { @@ -1552,11 +1559,15 @@ public class DeviceTest implements SerialInputOutputManager.Listener { 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; if (usbSerialDriver instanceof FtdiSerialDriver) { inputLinesSupported = true; - inputLinesConnected = usbSerialDriver.getPorts().size()==2; // I only have 74LS138 connected at FT2232 + inputLinesConnected = usbSerialDriver.getPorts().size() == 2; // I only have 74LS138 connected at FT2232 + } else if (usbSerialDriver instanceof Cp21xxSerialDriver) { + inputLinesSupported = true; + inputLinesConnected = usbSerialDriver.getPorts().size()==1; // I only have 74LS138 connected at CP2102 } else if (usbSerialDriver instanceof ProlificSerialDriver) { inputLinesSupported = true; inputLinesConnected = true; @@ -1572,6 +1583,9 @@ public class DeviceTest implements SerialInputOutputManager.Listener { supportedControlLines.add(UsbSerialPort.ControlLine.RI); } + // UsbSerialProber creates new UsbSerialPort objects which resets control lines, + // so the initial open has the output control lines unset. + // On additional close+open the output control lines can be retained. usbOpen(EnumSet.of(UsbOpenFlags.NO_CONTROL_LINE_INIT)); usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); @@ -1586,6 +1600,8 @@ public class DeviceTest implements SerialInputOutputManager.Listener { Thread.sleep(sleep); assertTrue(usbSerialPort.getRI()); } + + // control lines reset on initial open data = "none".getBytes(); assertEquals(inputLinesConnected ? EnumSet.of(UsbSerialPort.ControlLine.RI) @@ -1661,7 +1677,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener { usbWrite(data); assertThat(Arrays.toString(data), telnetRead(4), equalTo(data)); - // state retained over close/open + // control lines retained over close+open boolean inputRetained = inputLinesConnected; boolean outputRetained = true; if(usbSerialDriver instanceof FtdiSerialDriver) 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 6d47ceb..2d2d956 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 @@ -61,28 +61,26 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { public class Cp21xxSerialPort extends CommonUsbSerialPort { - private static final int DEFAULT_BAUD_RATE = 9600; - private static final int USB_WRITE_TIMEOUT_MILLIS = 5000; /* * Configuration Request Types */ private static final int REQTYPE_HOST_TO_DEVICE = 0x41; + private static final int REQTYPE_DEVICE_TO_HOST = 0xc1; /* * Configuration Request Codes */ private static final int SILABSER_IFC_ENABLE_REQUEST_CODE = 0x00; - private static final int SILABSER_SET_BAUDDIV_REQUEST_CODE = 0x01; private static final int SILABSER_SET_LINE_CTL_REQUEST_CODE = 0x03; private static final int SILABSER_SET_MHS_REQUEST_CODE = 0x07; private static final int SILABSER_SET_BAUDRATE = 0x1E; private static final int SILABSER_FLUSH_REQUEST_CODE = 0x12; - private static final int SILABSER_SET_DTR_RTS_REQUEST_CODE = 0x07; + private static final int SILABSER_GET_MDMSTS_REQUEST_CODE = 0x08; - private static final int FLUSH_READ_CODE = 0x0a; - private static final int FLUSH_WRITE_CODE = 0x05; + private static final int FLUSH_READ_CODE = 0x0a; + private static final int FLUSH_WRITE_CODE = 0x05; /* * SILABSER_IFC_ENABLE_REQUEST_CODE @@ -90,29 +88,23 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { private static final int UART_ENABLE = 0x0001; private static final int UART_DISABLE = 0x0000; - /* - * SILABSER_SET_BAUDDIV_REQUEST_CODE - */ - private static final int BAUD_RATE_GEN_FREQ = 0x384000; - /* * SILABSER_SET_MHS_REQUEST_CODE */ - private static final int MCR_DTR = 0x0001; - private static final int MCR_RTS = 0x0002; - private static final int MCR_ALL = 0x0003; - - private static final int CONTROL_WRITE_DTR = 0x0100; - private static final int CONTROL_WRITE_RTS = 0x0200; - - /* - * SILABSER_SET_DTR_RTS_REQUEST_CODE - */ private static final int DTR_ENABLE = 0x101; private static final int DTR_DISABLE = 0x100; private static final int RTS_ENABLE = 0x202; private static final int RTS_DISABLE = 0x200; + /* + * SILABSER_GET_MDMSTS_REQUEST_CODE + */ + private static final int STATUS_CTS = 0x10; + private static final int STATUS_DSR = 0x20; + private static final int STATUS_RI = 0x40; + private static final int STATUS_CD = 0x80; + + private boolean dtr = false; private boolean rts = false; @@ -137,6 +129,16 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { } } + private byte getStatus() throws IOException { + byte[] buffer = new byte[1]; + int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, SILABSER_GET_MDMSTS_REQUEST_CODE, 0, + mPortNumber, buffer, buffer.length, USB_WRITE_TIMEOUT_MILLIS); + if (result != 1) { + throw new IOException("Control transfer failed: " + SILABSER_GET_MDMSTS_REQUEST_CODE + " / " + 0 + " -> " + result); + } + return buffer[0]; + } + @Override protected void openInt(UsbDeviceConnection connection) throws IOException { mIsRestrictedPort = mDevice.getInterfaceCount() == 2 && mPortNumber == 1; @@ -159,9 +161,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { } setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_ENABLE); - setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, MCR_ALL | CONTROL_WRITE_DTR | CONTROL_WRITE_RTS); -// setConfigSingle(SILABSER_SET_BAUDDIV_REQUEST_CODE, BAUD_RATE_GEN_FREQ / DEFAULT_BAUD_RATE); -// setParameters(DEFAULT_BAUD_RATE, DEFAULT_DATA_BITS, DEFAULT_STOP_BITS, DEFAULT_PARITY); + setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, (dtr ? DTR_ENABLE : DTR_DISABLE) | (rts ? RTS_ENABLE : RTS_DISABLE)); } @Override @@ -260,17 +260,17 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { @Override public boolean getCD() throws IOException { - return false; + return (getStatus() & STATUS_CD) != 0; } @Override public boolean getCTS() throws IOException { - return false; + return (getStatus() & STATUS_CTS) != 0; } @Override public boolean getDSR() throws IOException { - return false; + return (getStatus() & STATUS_DSR) != 0; } @Override @@ -281,12 +281,12 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { @Override public void setDTR(boolean value) throws IOException { dtr = value; - setConfigSingle(SILABSER_SET_DTR_RTS_REQUEST_CODE, dtr ? DTR_ENABLE : DTR_DISABLE); + setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, dtr ? DTR_ENABLE : DTR_DISABLE); } @Override public boolean getRI() throws IOException { - return false; + return (getStatus() & STATUS_RI) != 0; } @Override @@ -297,23 +297,29 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { @Override public void setRTS(boolean value) throws IOException { rts = value; - setConfigSingle(SILABSER_SET_DTR_RTS_REQUEST_CODE, rts ? RTS_ENABLE : RTS_DISABLE); + setConfigSingle(SILABSER_SET_MHS_REQUEST_CODE, rts ? RTS_ENABLE : RTS_DISABLE); } @Override public EnumSet getControlLines() throws IOException { + byte status = getStatus(); EnumSet set = EnumSet.noneOf(ControlLine.class); if(rts) set.add(ControlLine.RTS); + if((status & STATUS_CTS) != 0) set.add(ControlLine.CTS); if(dtr) set.add(ControlLine.DTR); + if((status & STATUS_DSR) != 0) set.add(ControlLine.DSR); + if((status & STATUS_CD) != 0) set.add(ControlLine.CD); + if((status & STATUS_RI) != 0) set.add(ControlLine.RI); return set; } @Override public EnumSet getSupportedControlLines() throws IOException { - return EnumSet.of(ControlLine.RTS, ControlLine.DTR); + return EnumSet.allOf(ControlLine.class); } @Override + // note: only working on some devices, on other devices ignored w/o error public boolean purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException { int value = (purgeReadBuffers ? FLUSH_READ_CODE : 0) | (purgeWriteBuffers ? FLUSH_WRITE_CODE : 0);