diff --git a/usbSerialExamples/src/main/java/com/hoho/android/usbserial/examples/TerminalFragment.java b/usbSerialExamples/src/main/java/com/hoho/android/usbserial/examples/TerminalFragment.java index 6dff18e..62ede64 100644 --- a/usbSerialExamples/src/main/java/com/hoho/android/usbserial/examples/TerminalFragment.java +++ b/usbSerialExamples/src/main/java/com/hoho/android/usbserial/examples/TerminalFragment.java @@ -37,6 +37,7 @@ import com.hoho.android.usbserial.util.SerialInputOutputManager; import java.io.IOException; import java.util.Arrays; +import java.util.EnumSet; import java.util.concurrent.Executors; public class TerminalFragment extends Fragment implements SerialInputOutputManager.Listener { @@ -312,29 +313,42 @@ public class TerminalFragment extends Fragment implements SerialInputOutputManag if (btn.equals(rtsBtn)) { ctrl = "RTS"; usbSerialPort.setRTS(btn.isChecked()); } if (btn.equals(dtrBtn)) { ctrl = "DTR"; usbSerialPort.setDTR(btn.isChecked()); } } catch (IOException e) { - status("set" + ctrl + " failed: " + e.getMessage()); + status("set" + ctrl + "() failed: " + e.getMessage()); } } private boolean refresh() { - String ctrl = ""; try { - ctrl = "RTS"; rtsBtn.setChecked(usbSerialPort.getRTS()); - ctrl = "CTS"; ctsBtn.setChecked(usbSerialPort.getCTS()); - ctrl = "DTR"; dtrBtn.setChecked(usbSerialPort.getDTR()); - ctrl = "DSR"; dsrBtn.setChecked(usbSerialPort.getDSR()); - ctrl = "CD"; cdBtn.setChecked(usbSerialPort.getCD()); - ctrl = "RI"; riBtn.setChecked(usbSerialPort.getRI()); + EnumSet controlLines = usbSerialPort.getControlLines(); + rtsBtn.setChecked(controlLines.contains(UsbSerialPort.ControlLine.RTS)); + ctsBtn.setChecked(controlLines.contains(UsbSerialPort.ControlLine.CTS)); + dtrBtn.setChecked(controlLines.contains(UsbSerialPort.ControlLine.DTR)); + dsrBtn.setChecked(controlLines.contains(UsbSerialPort.ControlLine.DSR)); + cdBtn.setChecked(controlLines.contains(UsbSerialPort.ControlLine.CD)); + riBtn.setChecked(controlLines.contains(UsbSerialPort.ControlLine.RI)); } catch (IOException e) { - status("get" + ctrl + " failed: " + e.getMessage() + " -> stopped control line refresh"); + status("getControlLines() failed: " + e.getMessage() + " -> stopped control line refresh"); return false; } return true; } void start() { - if (connected && refresh()) - mainLooper.postDelayed(runnable, refreshInterval); + if (connected) { + try { + EnumSet controlLines = usbSerialPort.getSupportedControlLines(); + if (!controlLines.contains(UsbSerialPort.ControlLine.RTS)) rtsBtn.setVisibility(View.INVISIBLE); + if (!controlLines.contains(UsbSerialPort.ControlLine.CTS)) ctsBtn.setVisibility(View.INVISIBLE); + if (!controlLines.contains(UsbSerialPort.ControlLine.DTR)) dtrBtn.setVisibility(View.INVISIBLE); + if (!controlLines.contains(UsbSerialPort.ControlLine.DSR)) dsrBtn.setVisibility(View.INVISIBLE); + if (!controlLines.contains(UsbSerialPort.ControlLine.CD)) cdBtn.setVisibility(View.INVISIBLE); + if (!controlLines.contains(UsbSerialPort.ControlLine.RI)) riBtn.setVisibility(View.INVISIBLE); + } catch (IOException e) { + Toast.makeText(getActivity(), "getSupportedControlLines() failed: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } + if (refresh()) + mainLooper.postDelayed(runnable, refreshInterval); + } } void stop() { diff --git a/usbSerialForAndroid/build.gradle b/usbSerialForAndroid/build.gradle index 676f669..5f448b5 100644 --- a/usbSerialForAndroid/build.gradle +++ b/usbSerialForAndroid/build.gradle @@ -11,7 +11,7 @@ android { testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunnerArguments = [ // Raspi Windows LinuxVM ... - 'rfc2217_server_host': '192.168.0.100', + 'rfc2217_server_host': '192.168.0.110', 'rfc2217_server_nonstandard_baudrates': 'true', // true false false ] } 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 9244f4b..ab59a0b 100644 --- a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java +++ b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java @@ -1564,12 +1564,20 @@ public class DeviceTest implements SerialInputOutputManager.Listener { inputLinesSupported = true; inputLinesConnected = true; } + 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); + } 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); + assertEquals(supportedControlLines, usbSerialPort.getSupportedControlLines()); if(usbSerialDriver instanceof ProlificSerialDriver) { // the initial status is sometimes not available or wrong. // this is more likely if other tests have been executed before. @@ -1579,6 +1587,10 @@ public class DeviceTest implements SerialInputOutputManager.Listener { assertTrue(usbSerialPort.getRI()); } data = "none".getBytes(); + assertEquals(inputLinesConnected + ? EnumSet.of(UsbSerialPort.ControlLine.RI) + : EnumSet.noneOf(UsbSerialPort.ControlLine.class), + usbSerialPort.getControlLines()); assertFalse(usbSerialPort.getRTS()); assertFalse(usbSerialPort.getCTS()); assertFalse(usbSerialPort.getDTR()); @@ -1598,6 +1610,10 @@ public class DeviceTest implements SerialInputOutputManager.Listener { data = "rts ".getBytes(); usbSerialPort.setRTS(true); Thread.sleep(sleep); + assertEquals(inputLinesConnected + ? EnumSet.of(UsbSerialPort.ControlLine.RTS, UsbSerialPort.ControlLine.CTS) + : EnumSet.of(UsbSerialPort.ControlLine.RTS), + usbSerialPort.getControlLines()); assertTrue(usbSerialPort.getRTS()); assertEquals(usbSerialPort.getCTS(), inputLinesConnected); assertFalse(usbSerialPort.getDTR()); @@ -1612,6 +1628,10 @@ public class DeviceTest implements SerialInputOutputManager.Listener { data = "both".getBytes(); usbSerialPort.setDTR(true); Thread.sleep(sleep); + assertEquals(inputLinesConnected + ? EnumSet.of(UsbSerialPort.ControlLine.RTS, UsbSerialPort.ControlLine.DTR, UsbSerialPort.ControlLine.CD) + : EnumSet.of(UsbSerialPort.ControlLine.RTS, UsbSerialPort.ControlLine.DTR), + usbSerialPort.getControlLines()); assertTrue(usbSerialPort.getRTS()); assertFalse(usbSerialPort.getCTS()); assertTrue(usbSerialPort.getDTR()); @@ -1626,6 +1646,10 @@ public class DeviceTest implements SerialInputOutputManager.Listener { data = "dtr ".getBytes(); usbSerialPort.setRTS(false); Thread.sleep(sleep); + assertEquals(inputLinesConnected + ? EnumSet.of(UsbSerialPort.ControlLine.DTR, UsbSerialPort.ControlLine.DSR) + : EnumSet.of(UsbSerialPort.ControlLine.DTR), + usbSerialPort.getControlLines()); assertFalse(usbSerialPort.getRTS()); assertFalse(usbSerialPort.getCTS()); assertTrue(usbSerialPort.getDTR()); @@ -1646,6 +1670,10 @@ public class DeviceTest implements SerialInputOutputManager.Listener { usbOpen(EnumSet.of(UsbOpenFlags.NO_CONTROL_LINE_INIT, UsbOpenFlags.NO_IOMANAGER_THREAD)); usbParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE); + EnumSet retainedControlLines = EnumSet.noneOf(UsbSerialPort.ControlLine.class); + if(outputRetained) retainedControlLines.add(UsbSerialPort.ControlLine.DTR); + if(inputRetained) retainedControlLines.add(UsbSerialPort.ControlLine.DSR); + assertEquals(retainedControlLines, usbSerialPort.getControlLines()); assertFalse(usbSerialPort.getRTS()); assertFalse(usbSerialPort.getCTS()); assertEquals(usbSerialPort.getDTR(), outputRetained); 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 c4994ff..f646905 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 @@ -30,6 +30,7 @@ import android.util.Log; import java.io.IOException; import java.util.ArrayList; +import java.util.EnumSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -300,6 +301,18 @@ public class CdcAcmSerialDriver implements UsbSerialDriver { sendAcmControlMessage(SET_CONTROL_LINE_STATE, value, null); } + @Override + public EnumSet getControlLines() throws IOException { + EnumSet set = EnumSet.noneOf(ControlLine.class); + if(mRts) set.add(ControlLine.RTS); + if(mDtr) set.add(ControlLine.DTR); + return set; + } + + @Override + public EnumSet getSupportedControlLines() throws IOException { + return EnumSet.of(ControlLine.RTS, ControlLine.DTR); + } } public static Map getSupportedDevices() { 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 f0c6ba7..59ae9a7 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 @@ -28,6 +28,7 @@ import android.hardware.usb.UsbInterface; import java.io.IOException; import java.util.Collections; +import java.util.EnumSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -173,7 +174,7 @@ public class Ch34xSerialDriver implements UsbSerialDriver { } } - private byte getControlLines() throws IOException { + private byte getStatus() throws IOException { byte[] buffer = new byte[2]; int ret = controlIn(0x95, 0x0706, 0, buffer); if (ret < 0) @@ -304,17 +305,17 @@ public class Ch34xSerialDriver implements UsbSerialDriver { @Override public boolean getCD() throws IOException { - return (getControlLines() & GCL_CD) == 0; + return (getStatus() & GCL_CD) == 0; } @Override public boolean getCTS() throws IOException { - return (getControlLines() & GCL_CTS) == 0; + return (getStatus() & GCL_CTS) == 0; } @Override public boolean getDSR() throws IOException { - return (getControlLines() & GCL_DSR) == 0; + return (getStatus() & GCL_DSR) == 0; } @Override @@ -330,7 +331,7 @@ public class Ch34xSerialDriver implements UsbSerialDriver { @Override public boolean getRI() throws IOException { - return (getControlLines() & GCL_RI) == 0; + return (getStatus() & GCL_RI) == 0; } @Override @@ -344,6 +345,23 @@ public class Ch34xSerialDriver implements UsbSerialDriver { setControlLines(); } + @Override + public EnumSet getControlLines() throws IOException { + int status = getStatus(); + EnumSet set = EnumSet.noneOf(ControlLine.class); + if(rts) set.add(ControlLine.RTS); + if((status & GCL_CTS) == 0) set.add(ControlLine.CTS); + if(dtr) set.add(ControlLine.DTR); + if((status & GCL_DSR) == 0) set.add(ControlLine.DSR); + if((status & GCL_CD) == 0) set.add(ControlLine.CD); + if((status & GCL_RI) == 0) set.add(ControlLine.RI); + return set; + } + + @Override + public EnumSet getSupportedControlLines() throws IOException { + return EnumSet.allOf(ControlLine.class); + } } public static Map getSupportedDevices() { 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 acdc260..40d8c5c 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 @@ -29,6 +29,7 @@ import android.util.Log; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.EnumSet; /** * A base class shared by several driver implementations. @@ -249,6 +250,12 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort { @Override public abstract void setRTS(boolean value) throws IOException; + @Override + public abstract EnumSet getControlLines() throws IOException; + + @Override + public abstract EnumSet getSupportedControlLines() throws IOException; + @Override public boolean purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException { return false; 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 1ce0d4c..6d47ceb 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 @@ -29,6 +29,7 @@ import android.hardware.usb.UsbInterface; import java.io.IOException; import java.util.ArrayList; +import java.util.EnumSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -299,6 +300,19 @@ public class Cp21xxSerialDriver implements UsbSerialDriver { setConfigSingle(SILABSER_SET_DTR_RTS_REQUEST_CODE, rts ? RTS_ENABLE : RTS_DISABLE); } + @Override + public EnumSet getControlLines() throws IOException { + EnumSet set = EnumSet.noneOf(ControlLine.class); + if(rts) set.add(ControlLine.RTS); + if(dtr) set.add(ControlLine.DTR); + return set; + } + + @Override + public EnumSet getSupportedControlLines() throws IOException { + return EnumSet.of(ControlLine.RTS, ControlLine.DTR); + } + @Override public boolean purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException { int value = (purgeReadBuffers ? FLUSH_READ_CODE : 0) 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 adfc9bd..bb60df9 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 @@ -28,6 +28,7 @@ import android.util.Log; import java.io.IOException; import java.util.ArrayList; +import java.util.EnumSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -527,6 +528,24 @@ public class FtdiSerialDriver implements UsbSerialDriver { mRtsState = value; } + @Override + public EnumSet getControlLines() throws IOException { + int status = getModemStatus(); + EnumSet set = EnumSet.noneOf(ControlLine.class); + if(mRtsState) set.add(ControlLine.RTS); + if((status & SIO_MODEM_STATUS_CTS) != 0) set.add(ControlLine.CTS); + if(mDtrState) set.add(ControlLine.DTR); + if((status & SIO_MODEM_STATUS_DSR) != 0) set.add(ControlLine.DSR); + if((status & SIO_MODEM_STATUS_RLSD) != 0) set.add(ControlLine.CD); + if((status & SIO_MODEM_STATUS_RI) != 0) set.add(ControlLine.RI); + return set; + } + + @Override + public EnumSet getSupportedControlLines() throws IOException { + return EnumSet.allOf(ControlLine.class); + } + @Override public boolean purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException { if (purgeWriteBuffers) { 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 cd3c548..9229b52 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 @@ -37,6 +37,7 @@ import android.util.Log; import java.io.IOException; import java.lang.reflect.Method; import java.util.Collections; +import java.util.EnumSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -426,7 +427,7 @@ public class ProlificSerialDriver implements UsbSerialDriver { @Override public boolean getDTR() throws IOException { - return ((mControlLinesValue & CONTROL_DTR) == CONTROL_DTR); + return (mControlLinesValue & CONTROL_DTR) != 0; } @Override @@ -447,7 +448,7 @@ public class ProlificSerialDriver implements UsbSerialDriver { @Override public boolean getRTS() throws IOException { - return ((mControlLinesValue & CONTROL_RTS) == CONTROL_RTS); + return (mControlLinesValue & CONTROL_RTS) != 0; } @Override @@ -461,6 +462,25 @@ public class ProlificSerialDriver implements UsbSerialDriver { setControlLines(newControlLinesValue); } + + @Override + public EnumSet getControlLines() throws IOException { + int status = getStatus(); + EnumSet set = EnumSet.noneOf(ControlLine.class); + if((mControlLinesValue & CONTROL_RTS) != 0) set.add(ControlLine.RTS); + if((status & STATUS_FLAG_CTS) != 0) set.add(ControlLine.CTS); + if((mControlLinesValue & CONTROL_DTR) != 0) set.add(ControlLine.DTR); + if((status & STATUS_FLAG_DSR) != 0) set.add(ControlLine.DSR); + if((status & STATUS_FLAG_CD) != 0) set.add(ControlLine.CD); + if((status & STATUS_FLAG_RI) != 0) set.add(ControlLine.RI); + return set; + } + + @Override + public EnumSet getSupportedControlLines() throws IOException { + return EnumSet.allOf(ControlLine.class); + } + @Override public boolean purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException { if (purgeWriteBuffers) { 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 03ded49..83e8090 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 @@ -27,6 +27,7 @@ import android.hardware.usb.UsbManager; import java.io.Closeable; import java.io.IOException; +import java.util.EnumSet; /** * Interface for a single serial port. @@ -86,6 +87,12 @@ public interface UsbSerialPort extends Closeable { /** 2 stop bits. */ public static final int STOPBITS_2 = 2; + /** values for get[Supported]ControlLines() */ + public enum ControlLine { RTS, CTS, DTR, DSR, CD, RI }; + + /** + * Returns the driver used by this port. + */ public UsbSerialDriver getDriver(); /** @@ -100,6 +107,9 @@ public interface UsbSerialPort extends Closeable { /** * The serial number of the underlying UsbDeviceConnection, or {@code null}. + * + * @return value from {@link UsbDeviceConnection#getSerial()} + * @throws SecurityException starting with target SDK 29 (Android 10) if permission for USB device is not granted */ public String getSerial(); @@ -189,8 +199,7 @@ public interface UsbSerialPort extends Closeable { public boolean getDTR() throws IOException; /** - * Sets the DTR (Data Terminal Ready) bit on the underlying UART, if - * supported. + * Sets the DTR (Data Terminal Ready) bit on the underlying UART, if supported. * * @param value the value to set * @throws IOException if an error occurred during writing @@ -214,14 +223,30 @@ public interface UsbSerialPort extends Closeable { public boolean getRTS() throws IOException; /** - * Sets the RTS (Request To Send) bit on the underlying UART, if - * supported. + * Sets the RTS (Request To Send) bit on the underlying UART, if supported. * * @param value the value to set * @throws IOException if an error occurred during writing */ public void setRTS(boolean value) throws IOException; + /** + * Gets all control line values from the underlying UART, if supported. + * Requires less USB calls than calling getRTS() + ... + getRI() individually. + * + * @return EnumSet.contains(...) is {@code true} if set, else {@code false} + * @throws IOException + */ + public EnumSet getControlLines() throws IOException; + + /** + * Gets all control line supported flags. + * + * @return EnumSet.contains(...) is {@code true} if supported, else {@code false} + * @throws IOException + */ + public EnumSet getSupportedControlLines() throws IOException; + /** * purge non-transmitted output data and / or non-read input data * @param purgeWriteBuffers {@code true} to discard non-transmitted output data