1
0
mirror of https://github.com/mik3y/usb-serial-for-android synced 2025-06-08 00:16:13 +00:00

PL2303(HX) support non-standard baud rates

This commit is contained in:
kai-morich 2020-09-27 17:34:29 +02:00
parent 1adf2a9b98
commit 732e138630
3 changed files with 89 additions and 58 deletions

View File

@ -302,8 +302,25 @@ public class DeviceTest {
28800, 38400, 57600, 115200, 128000, 134400, 161280, 201600, 230400, 268800, 28800, 38400, 57600, 115200, 128000, 134400, 161280, 201600, 230400, 268800,
403200, 460800, 614400, 806400, 921600, 1228800, 2457600, 3000000, /*6000000*/ 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) { for(int baudRate : baudRates) {
usb.open();
int readWait = 500; int readWait = 500;
if(baudRate < 300) readWait = 1000; if(baudRate < 300) readWait = 1000;
if(baudRate < 150) readWait = 2000; if(baudRate < 150) readWait = 2000;
@ -311,40 +328,31 @@ public class DeviceTest {
usb.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE); usb.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);
doReadWrite(String.valueOf(baudRate), readWait); doReadWrite(String.valueOf(baudRate), readWait);
try { usb.setParameters(baudRate + 1, 8, 1, UsbSerialPort.PARITY_NONE);
usb.setParameters(baudRate + 1, 8, 1, UsbSerialPort.PARITY_NONE); doReadWrite(String.valueOf(baudRate + 1), readWait);
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);
// silent fallback to 9600 for unsupported baud rates // silent fallback to 9600 for unsupported baud rates
telnet.setParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE); telnet.setParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE);
usb.setParameters(baudRate + 1 + (1<<29), 8, 1, UsbSerialPort.PARITY_NONE); usb.setParameters(baudRate + 1 + (1<<29), 8, 1, UsbSerialPort.PARITY_NONE);
doReadWrite(String.valueOf(baudRate + 1) + " + 1<<29", readWait); doReadWrite(String.valueOf(baudRate + 1) + " + 1<<29", readWait);
usb.close();
} }
// some PL2303... data sheets mention additional baud rates, others don't // some PL2303... data sheets mention additional baud rates, others don't
// they do not work with my devices and linux driver also excludes them // 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}; baudRates = new int[]{110, 56000, 256000};
for(int baudRate : baudRates) { for(int baudRate : baudRates) {
int readWait = 500; int readWait = 500;
if(baudRate < 300) readWait = 1000; if(baudRate < 300) readWait = 1000;
if(baudRate < 150) readWait = 2000; if(baudRate < 150) readWait = 2000;
try { telnet.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);
usb.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE); usb.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);
fail("unsupported baud rate error expected "+baudRate); doReadWrite(String.valueOf(baudRate), readWait);
} catch(UnsupportedOperationException ignored) {}
// silent fallback to 9600 for unsupported baud rates // 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); usb.setParameters(baudRate + (1<<29), 8, 1, UsbSerialPort.PARITY_NONE);
doReadWrite(String.valueOf(baudRate ) + " + 1<<29", readWait); doReadWrite(String.valueOf(baudRate ) + " + 1<<29", readWait);
} }
usb.close();
} }
@Test @Test
@ -460,36 +468,29 @@ public class DeviceTest {
doReadWrite(baudRate+"/8N1"); doReadWrite(baudRate+"/8N1");
} }
if(rfc2217_server_nonstandard_baudrates && !isCp21xxRestrictedPort) { if(rfc2217_server_nonstandard_baudrates && !isCp21xxRestrictedPort) {
if (usb.serialDriver instanceof ProlificSerialDriver) { usb.setParameters(42000, 8, 1, UsbSerialPort.PARITY_NONE);
try { telnet.setParameters(42000, 8, 1, UsbSerialPort.PARITY_NONE);
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[] buf1 = "abc".getBytes();
byte[] buf2 = "ABC".getBytes(); byte[] buf2 = "ABC".getBytes();
byte[] data1, data2; byte[] data1, data2;
usb.write(buf1); usb.write(buf1);
data1 = telnet.read(); data1 = telnet.read();
telnet.write(buf2); telnet.write(buf2);
data2 = usb.read(); data2 = usb.read();
if (usb.serialDriver instanceof Cp21xxSerialDriver) { if (usb.serialDriver instanceof Cp21xxSerialDriver) {
if (usb.serialDriver.getPorts().size() > 1) { if (usb.serialDriver.getPorts().size() > 1) {
// supported on cp2105 first port // 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", data1, equalTo(buf1));
assertThat("42000/8N1", data2, equalTo(buf2)); 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 { // non matching baud rate

View File

@ -176,7 +176,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
private void setBaudrate(int baudRate) throws IOException { private void setBaudrate(int baudRate) throws IOException {
int divisor, subdivisor, effectiveBaudRate; int divisor, subdivisor, effectiveBaudRate;
if (baudRate > 3500000) { if (baudRate > 3500000) {
throw new IOException("Baud rate to high"); throw new UnsupportedOperationException("Baud rate to high");
} else if(baudRate >= 2500000) { } else if(baudRate >= 2500000) {
divisor = 0; divisor = 0;
subdivisor = 0; subdivisor = 0;
@ -191,13 +191,13 @@ public class FtdiSerialDriver implements UsbSerialDriver {
subdivisor = divisor & 0x07; subdivisor = divisor & 0x07;
divisor >>= 3; divisor >>= 3;
if (divisor > 0x3fff) // exceeds bit 13 at 183 baud 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 = (24000000 << 1) / ((divisor << 3) + subdivisor);
effectiveBaudRate = (effectiveBaudRate +1) >> 1; effectiveBaudRate = (effectiveBaudRate +1) >> 1;
} }
double baudRateError = Math.abs(1.0 - (effectiveBaudRate / (double)baudRate)); double baudRateError = Math.abs(1.0 - (effectiveBaudRate / (double)baudRate));
if(baudRateError >= 0.031) // can happen only > 1.5Mbaud 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 value = divisor;
int index = 0; int index = 0;
switch(subdivisor) { switch(subdivisor) {

View File

@ -19,6 +19,7 @@ import android.util.Log;
import com.hoho.android.usbserial.BuildConfig; import com.hoho.android.usbserial.BuildConfig;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -34,7 +35,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
28800, 38400, 57600, 115200, 128000, 134400, 161280, 201600, 230400, 268800, 28800, 38400, 57600, 115200, 128000, 134400, 161280, 201600, 230400, 268800,
403200, 460800, 614400, 806400, 921600, 1228800, 2457600, 3000000, 6000000 403200, 460800, 614400, 806400, 921600, 1228800, 2457600, 3000000, 6000000
}; };
private enum DeviceType { DEVICE_TYPE_01, DEVICE_TYPE_HX};
private final UsbDevice mDevice; private final UsbDevice mDevice;
private final UsbSerialPort mPort; private final UsbSerialPort mPort;
@ -89,11 +90,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
private static final int STATUS_BUFFER_SIZE = 10; private static final int STATUS_BUFFER_SIZE = 10;
private static final int STATUS_BYTE_IDX = 8; private static final int STATUS_BYTE_IDX = 8;
private static final int DEVICE_TYPE_HX = 0; private DeviceType mDeviceType = DeviceType.DEVICE_TYPE_HX;
private static final int DEVICE_TYPE_0 = 1;
private static final int DEVICE_TYPE_1 = 2;
private int mDeviceType = DEVICE_TYPE_HX;
private UsbEndpoint mInterruptEndpoint; private UsbEndpoint mInterruptEndpoint;
private int mControlLinesValue = 0; private int mControlLinesValue = 0;
private int mBaudRate = -1, mDataBits = -1, mStopBits = -1, mParity = -1; private int mBaudRate = -1, mDataBits = -1, mStopBits = -1, mParity = -1;
@ -172,7 +169,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
vendorIn(0x8383, 0, 1); vendorIn(0x8383, 0, 1);
vendorOut(0, 1, null); vendorOut(0, 1, null);
vendorOut(1, 0, 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 { private void setControlLines(int newControlLinesValue) throws IOException {
@ -272,22 +269,22 @@ public class ProlificSerialDriver implements UsbSerialDriver {
} }
if (mDevice.getDeviceClass() == 0x02) { if (mDevice.getDeviceClass() == 0x02) {
mDeviceType = DEVICE_TYPE_0; mDeviceType = DeviceType.DEVICE_TYPE_01;
} else { } else {
byte[] rawDescriptors = connection.getRawDescriptors(); byte[] rawDescriptors = connection.getRawDescriptors();
if(rawDescriptors == null || rawDescriptors.length <8) { if(rawDescriptors == null || rawDescriptors.length <8) {
Log.w(TAG, "Could not get device descriptors, Assuming that it is a HX device"); 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 { } else {
byte maxPacketSize0 = rawDescriptors[7]; byte maxPacketSize0 = rawDescriptors[7];
if (maxPacketSize0 == 64) { if (maxPacketSize0 == 64) {
mDeviceType = DEVICE_TYPE_HX; mDeviceType = DeviceType.DEVICE_TYPE_HX;
} else if ((mDevice.getDeviceClass() == 0x00) } else if ((mDevice.getDeviceClass() == 0x00)
|| (mDevice.getDeviceClass() == 0xff)) { || (mDevice.getDeviceClass() == 0xff)) {
mDeviceType = DEVICE_TYPE_1; mDeviceType = DeviceType.DEVICE_TYPE_01;
} else { } else {
Log.w(TAG, "Could not detect PL2303 subtype, Assuming that it is a HX device"); 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 @@ public class ProlificSerialDriver implements UsbSerialDriver {
return 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 @Override