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 14c7f450..c6a1af3b 100644 --- a/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java +++ b/usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java @@ -302,8 +302,25 @@ public void prolificBaudRate() throws Exception { 28800, 38400, 57600, 115200, 128000, 134400, 161280, 201600, 230400, 268800, 403200, 460800, 614400, 806400, 921600, 1228800, 2457600, 3000000, /*6000000*/ }; + usb.open(); + + try { + usb.setParameters(45, 8, 1, UsbSerialPort.PARITY_NONE); + fail("baud rate to low expected"); + } catch(UnsupportedOperationException ignored) {} + usb.setParameters(46, 8, 1, UsbSerialPort.PARITY_NONE); + usb.setParameters(384_000_000, 8, 1, UsbSerialPort.PARITY_NONE); + try { + usb.setParameters(384_000_001, 8, 1, UsbSerialPort.PARITY_NONE); + fail("baud rate to high expected"); + } catch(UnsupportedOperationException ignored) {} + usb.setParameters(11_636_363, 8, 1, UsbSerialPort.PARITY_NONE); + try { + usb.setParameters(11_636_364, 8, 1, UsbSerialPort.PARITY_NONE); + fail("baud rate deviation to high expected"); + } catch(UnsupportedOperationException ignored) {} + for(int baudRate : baudRates) { - usb.open(); int readWait = 500; if(baudRate < 300) readWait = 1000; if(baudRate < 150) readWait = 2000; @@ -311,40 +328,31 @@ public void prolificBaudRate() throws Exception { usb.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE); doReadWrite(String.valueOf(baudRate), readWait); - try { - usb.setParameters(baudRate + 1, 8, 1, UsbSerialPort.PARITY_NONE); - fail("unsupported baud rate error expected "+baudRate); - } catch(UnsupportedOperationException ignored) {} - - usb.setParameters(baudRate + (1<<29), 8, 1, UsbSerialPort.PARITY_NONE); - doReadWrite(String.valueOf(baudRate) + " + 1<<29", readWait); + usb.setParameters(baudRate + 1, 8, 1, UsbSerialPort.PARITY_NONE); + doReadWrite(String.valueOf(baudRate + 1), readWait); // silent fallback to 9600 for unsupported baud rates telnet.setParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE); usb.setParameters(baudRate + 1 + (1<<29), 8, 1, UsbSerialPort.PARITY_NONE); doReadWrite(String.valueOf(baudRate + 1) + " + 1<<29", readWait); - usb.close(); } // some PL2303... data sheets mention additional baud rates, others don't // they do not work with my devices and linux driver also excludes them - usb.open(); - telnet.setParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE); baudRates = new int[]{110, 56000, 256000}; for(int baudRate : baudRates) { int readWait = 500; if(baudRate < 300) readWait = 1000; if(baudRate < 150) readWait = 2000; - try { - usb.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE); - fail("unsupported baud rate error expected "+baudRate); - } catch(UnsupportedOperationException ignored) {} + telnet.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE); + usb.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE); + doReadWrite(String.valueOf(baudRate), readWait); // silent fallback to 9600 for unsupported baud rates + telnet.setParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE); usb.setParameters(baudRate + (1<<29), 8, 1, UsbSerialPort.PARITY_NONE); doReadWrite(String.valueOf(baudRate ) + " + 1<<29", readWait); } - usb.close(); } @Test @@ -460,36 +468,29 @@ else if (usb.serialDriver instanceof CdcAcmSerialDriver) doReadWrite(baudRate+"/8N1"); } if(rfc2217_server_nonstandard_baudrates && !isCp21xxRestrictedPort) { - if (usb.serialDriver instanceof ProlificSerialDriver) { - try { - usb.setParameters(42000, 8, 1, UsbSerialPort.PARITY_NONE); - fail("unsupported baud rate error expected"); - } catch (UnsupportedOperationException ignored) {} - } else { - usb.setParameters(42000, 8, 1, UsbSerialPort.PARITY_NONE); - telnet.setParameters(42000, 8, 1, UsbSerialPort.PARITY_NONE); - - byte[] buf1 = "abc".getBytes(); - byte[] buf2 = "ABC".getBytes(); - byte[] data1, data2; - usb.write(buf1); - data1 = telnet.read(); - telnet.write(buf2); - data2 = usb.read(); - if (usb.serialDriver instanceof Cp21xxSerialDriver) { - if (usb.serialDriver.getPorts().size() > 1) { - // supported on cp2105 first port - assertThat("42000/8N1", data1, equalTo(buf1)); - assertThat("42000/8N1", data2, equalTo(buf2)); - } else { - // not supported on cp2102 - assertNotEquals(data1, buf1); - assertNotEquals(data2, buf2); - } - } else { + usb.setParameters(42000, 8, 1, UsbSerialPort.PARITY_NONE); + telnet.setParameters(42000, 8, 1, UsbSerialPort.PARITY_NONE); + + byte[] buf1 = "abc".getBytes(); + byte[] buf2 = "ABC".getBytes(); + byte[] data1, data2; + usb.write(buf1); + data1 = telnet.read(); + telnet.write(buf2); + data2 = usb.read(); + if (usb.serialDriver instanceof Cp21xxSerialDriver) { + if (usb.serialDriver.getPorts().size() > 1) { + // supported on cp2105 first port assertThat("42000/8N1", data1, equalTo(buf1)); assertThat("42000/8N1", data2, equalTo(buf2)); + } else { + // not supported on cp2102 + assertNotEquals(data1, buf1); + assertNotEquals(data2, buf2); } + } else { + assertThat("42000/8N1", data1, equalTo(buf1)); + assertThat("42000/8N1", data2, equalTo(buf2)); } } { // non matching baud rate 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 c0f257c0..64b2b843 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 @@ -176,7 +176,7 @@ private int readFilter(byte[] buffer, int totalBytesRead) throws IOException { private void setBaudrate(int baudRate) throws IOException { int divisor, subdivisor, effectiveBaudRate; if (baudRate > 3500000) { - throw new IOException("Baud rate to high"); + throw new UnsupportedOperationException("Baud rate to high"); } else if(baudRate >= 2500000) { divisor = 0; subdivisor = 0; @@ -191,13 +191,13 @@ private void setBaudrate(int baudRate) throws IOException { subdivisor = divisor & 0x07; divisor >>= 3; if (divisor > 0x3fff) // exceeds bit 13 at 183 baud - throw new IOException("Baud rate to low"); + throw new UnsupportedOperationException("Baud rate to low"); effectiveBaudRate = (24000000 << 1) / ((divisor << 3) + subdivisor); effectiveBaudRate = (effectiveBaudRate +1) >> 1; } double baudRateError = Math.abs(1.0 - (effectiveBaudRate / (double)baudRate)); if(baudRateError >= 0.031) // can happen only > 1.5Mbaud - throw new IOException(String.format("baud rate deviation %.1f%% is higher than allowed 3%%", baudRateError*100)); + throw new UnsupportedOperationException(String.format("Baud rate deviation %.1f%% is higher than allowed 3%%", baudRateError*100)); int value = divisor; int index = 0; switch(subdivisor) { 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 830553fe..88e517dd 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 @@ -19,6 +19,7 @@ import com.hoho.android.usbserial.BuildConfig; import java.io.IOException; +import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.LinkedHashMap; @@ -34,7 +35,7 @@ public class ProlificSerialDriver implements UsbSerialDriver { 28800, 38400, 57600, 115200, 128000, 134400, 161280, 201600, 230400, 268800, 403200, 460800, 614400, 806400, 921600, 1228800, 2457600, 3000000, 6000000 }; - + private enum DeviceType { DEVICE_TYPE_01, DEVICE_TYPE_HX}; private final UsbDevice mDevice; private final UsbSerialPort mPort; @@ -89,11 +90,7 @@ class ProlificSerialPort extends CommonUsbSerialPort { private static final int STATUS_BUFFER_SIZE = 10; private static final int STATUS_BYTE_IDX = 8; - private static final int DEVICE_TYPE_HX = 0; - private static final int DEVICE_TYPE_0 = 1; - private static final int DEVICE_TYPE_1 = 2; - - private int mDeviceType = DEVICE_TYPE_HX; + private DeviceType mDeviceType = DeviceType.DEVICE_TYPE_HX; private UsbEndpoint mInterruptEndpoint; private int mControlLinesValue = 0; private int mBaudRate = -1, mDataBits = -1, mStopBits = -1, mParity = -1; @@ -172,7 +169,7 @@ private void doBlackMagic() throws IOException { vendorIn(0x8383, 0, 1); vendorOut(0, 1, null); vendorOut(1, 0, null); - vendorOut(2, (mDeviceType == DEVICE_TYPE_HX) ? 0x44 : 0x24, null); + vendorOut(2, (mDeviceType == DeviceType.DEVICE_TYPE_HX) ? 0x44 : 0x24, null); } private void setControlLines(int newControlLinesValue) throws IOException { @@ -272,22 +269,22 @@ public void openInt(UsbDeviceConnection connection) throws IOException { } if (mDevice.getDeviceClass() == 0x02) { - mDeviceType = DEVICE_TYPE_0; + mDeviceType = DeviceType.DEVICE_TYPE_01; } else { byte[] rawDescriptors = connection.getRawDescriptors(); if(rawDescriptors == null || rawDescriptors.length <8) { Log.w(TAG, "Could not get device descriptors, Assuming that it is a HX device"); - mDeviceType = DEVICE_TYPE_HX; + mDeviceType = DeviceType.DEVICE_TYPE_HX; } else { byte maxPacketSize0 = rawDescriptors[7]; if (maxPacketSize0 == 64) { - mDeviceType = DEVICE_TYPE_HX; + mDeviceType = DeviceType.DEVICE_TYPE_HX; } else if ((mDevice.getDeviceClass() == 0x00) || (mDevice.getDeviceClass() == 0xff)) { - mDeviceType = DEVICE_TYPE_1; + mDeviceType = DeviceType.DEVICE_TYPE_01; } else { Log.w(TAG, "Could not detect PL2303 subtype, Assuming that it is a HX device"); - mDeviceType = DEVICE_TYPE_HX; + mDeviceType = DeviceType.DEVICE_TYPE_HX; } } } @@ -328,7 +325,40 @@ private int filterBaudRate(int baudRate) { return baudRate; } } - throw new UnsupportedOperationException("Unsupported baud rate: " + baudRate); + /* + * Formula taken from Linux + FreeBSD. + * baudrate = baseline / (mantissa * 4^exponent) + * where + * mantissa = buf[8:0] + * exponent = buf[11:9] + * + * Note: The formula does not work for all PL2303 variants. + * Ok for PL2303HX. Not ok for PL2303TA. Other variants unknown. + */ + int baseline, mantissa, exponent; + baseline = 12000000 * 32; + mantissa = baseline / baudRate; + if (mantissa == 0) { // > unrealistic 384 MBaud + throw new UnsupportedOperationException("Baud rate to high"); + } + exponent = 0; + while (mantissa >= 512) { + if (exponent < 7) { + mantissa >>= 2; /* divide by 4 */ + exponent++; + } else { // < 45.8 baud + throw new UnsupportedOperationException("Baud rate to low"); + } + } + int effectiveBaudRate = (baseline / mantissa) >> (exponent << 1); + double baudRateError = Math.abs(1.0 - (effectiveBaudRate / (double)baudRate)); + if(baudRateError >= 0.031) // > unrealistic 11.6 Mbaud + throw new UnsupportedOperationException(String.format("Baud rate deviation %.1f%% is higher than allowed 3%%", baudRateError*100)); + int buf = mantissa + (exponent<<9) + (1<<31); + + Log.d(TAG, String.format("baud rate=%d, effective=%d, error=%.1f%%, value=0x%08x, mantissa=%d, exponent=%d", + baudRate, effectiveBaudRate, baudRateError*100, buf, mantissa, exponent)); + return buf; } @Override