Skip to content

Commit

Permalink
support PL2303GC/GB/GT/GL/GE/GS
Browse files Browse the repository at this point in the history
  • Loading branch information
kai-morich committed May 13, 2021
1 parent 2f23bdf commit c82cd28
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 28 deletions.
10 changes: 8 additions & 2 deletions usbSerialExamples/src/main/res/xml/device_filter.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@
<usb-device vendor-id="4292" product-id="60016" /> <!-- 0xea70: CP2105 -->
<usb-device vendor-id="4292" product-id="60017" /> <!-- 0xea71: CP2108 -->

<!-- 0x067B / 0x2303: Prolific PL2303 -->
<usb-device vendor-id="1659" product-id="8963" />
<!-- 0x067B / 0x23?3: Prolific PL2303x -->
<usb-device vendor-id="1659" product-id="8963" /> <!-- 0x2303: PL2303HX, HXD, TA, ... -->
<usb-device vendor-id="1659" product-id="9123" /> <!-- 0x23a3: PL2303GC -->
<usb-device vendor-id="1659" product-id="9139" /> <!-- 0x23b3: PL2303GB -->
<usb-device vendor-id="1659" product-id="9155" /> <!-- 0x23c3: PL2303GT -->
<usb-device vendor-id="1659" product-id="9171" /> <!-- 0x23d3: PL2303GL -->
<usb-device vendor-id="1659" product-id="9187" /> <!-- 0x23e3: PL2303GE -->
<usb-device vendor-id="1659" product-id="9203" /> <!-- 0x23f3: PL2303GS -->

<!-- 0x1a86 / 0x?523: Qinheng CH34x -->
<usb-device vendor-id="6790" product-id="21795" /> <!-- 0x5523: CH341A -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ public void prolificBaudRate() throws Exception {
403200, 460800, 614400, 806400, 921600, 1228800, 2457600, 3000000, /*6000000*/
};
usb.open();
Assume.assumeFalse("only for non PL2303G*", ProlificWrapper.isDeviceTypeHxn(usb.serialPort)); // HXN does not use divisor

int minBaudRate = ProlificWrapper.isDeviceTypeT(usb.serialPort) ? 6 : 46;
try {
Expand Down Expand Up @@ -1675,7 +1676,7 @@ public void wrongDriver() throws Exception {

@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 ...
input control lines with a binary decoder 74LS42, 74LS138, 74LS139, 74HC... or ...
in
A0 = RTS
A1 = DTR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@ public static boolean isDeviceTypeT(UsbSerialPort serialPort) {
ProlificSerialDriver.ProlificSerialPort prolificSerialPort = (ProlificSerialDriver.ProlificSerialPort) serialPort;
return prolificSerialPort.mDeviceType == ProlificSerialDriver.DeviceType.DEVICE_TYPE_T;
}

public static boolean isDeviceTypeHxn(UsbSerialPort serialPort) {
ProlificSerialDriver.ProlificSerialPort prolificSerialPort = (ProlificSerialDriver.ProlificSerialPort) serialPort;
return prolificSerialPort.mDeviceType == ProlificSerialDriver.DeviceType.DEVICE_TYPE_HXN;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,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
};
protected enum DeviceType { DEVICE_TYPE_01, DEVICE_TYPE_T, DEVICE_TYPE_HX}
protected enum DeviceType { DEVICE_TYPE_01, DEVICE_TYPE_T, DEVICE_TYPE_HX, DEVICE_TYPE_HXN}

private final UsbDevice mDevice;
private final UsbSerialPort mPort;
Expand All @@ -62,34 +62,50 @@ class ProlificSerialPort extends CommonUsbSerialPort {

private static final int USB_RECIP_INTERFACE = 0x01;

private static final int PROLIFIC_VENDOR_READ_REQUEST = 0x01;
private static final int PROLIFIC_VENDOR_WRITE_REQUEST = 0x01;
private static final int VENDOR_READ_REQUEST = 0x01;
private static final int VENDOR_WRITE_REQUEST = 0x01;
private static final int VENDOR_READ_HXN_REQUEST = 0x81;
private static final int VENDOR_WRITE_HXN_REQUEST = 0x80;

private static final int PROLIFIC_VENDOR_OUT_REQTYPE = UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR;
private static final int PROLIFIC_VENDOR_IN_REQTYPE = UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_VENDOR;
private static final int PROLIFIC_CTRL_OUT_REQTYPE = UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;
private static final int VENDOR_OUT_REQTYPE = UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR;
private static final int VENDOR_IN_REQTYPE = UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_VENDOR;
private static final int CTRL_OUT_REQTYPE = UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;

private static final int WRITE_ENDPOINT = 0x02;
private static final int READ_ENDPOINT = 0x83;
private static final int INTERRUPT_ENDPOINT = 0x81;

private static final int FLUSH_RX_REQUEST = 0x08; // RX @ Prolific device = write @ usb-serial-for-android library
private static final int RESET_HXN_REQUEST = 0x07;
private static final int FLUSH_RX_REQUEST = 0x08;
private static final int FLUSH_TX_REQUEST = 0x09;

private static final int SET_LINE_REQUEST = 0x20; // same as CDC SET_LINE_CODING
private static final int SET_CONTROL_REQUEST = 0x22; // same as CDC SET_CONTROL_LINE_STATE
private static final int SEND_BREAK_REQUEST = 0x23; // same as CDC SEND_BREAK
private static final int GET_CONTROL_HXN_REQUEST = 0x80;
private static final int GET_CONTROL_REQUEST = 0x87;
private static final int STATUS_NOTIFICATION = 0xa1; // similar to CDC SERIAL_STATE but different length

/* RESET_HXN_REQUEST */
private static final int RESET_HXN_RX_PIPE = 1;
private static final int RESET_HXN_TX_PIPE = 2;

/* SET_CONTROL_REQUEST */
private static final int CONTROL_DTR = 0x01;
private static final int CONTROL_RTS = 0x02;

/* GET_CONTROL_REQUEST */
private static final int GET_CONTROL_FLAG_CD = 0x02;
private static final int GET_CONTROL_FLAG_DSR = 0x04;
private static final int GET_CONTROL_FLAG_RI = 0x01;
private static final int GET_CONTROL_FLAG_CTS = 0x08;

/* GET_CONTROL_HXN_REQUEST */
private static final int GET_CONTROL_HXN_FLAG_CD = 0x40;
private static final int GET_CONTROL_HXN_FLAG_DSR = 0x20;
private static final int GET_CONTROL_HXN_FLAG_RI = 0x80;
private static final int GET_CONTROL_HXN_FLAG_CTS = 0x08;

/* interrupt endpoint read */
private static final int STATUS_FLAG_CD = 0x01;
private static final int STATUS_FLAG_DSR = 0x02;
private static final int STATUS_FLAG_RI = 0x08;
Expand Down Expand Up @@ -137,22 +153,35 @@ private void outControlTransfer(int requestType, int request, int value, int ind
}

private byte[] vendorIn(int value, int index, int length) throws IOException {
return inControlTransfer(PROLIFIC_VENDOR_IN_REQTYPE, PROLIFIC_VENDOR_READ_REQUEST, value, index, length);
int request = (mDeviceType == DeviceType.DEVICE_TYPE_HXN) ? VENDOR_READ_HXN_REQUEST : VENDOR_READ_REQUEST;
return inControlTransfer(VENDOR_IN_REQTYPE, request, value, index, length);
}

private void vendorOut(int value, int index, byte[] data) throws IOException {
outControlTransfer(PROLIFIC_VENDOR_OUT_REQTYPE, PROLIFIC_VENDOR_WRITE_REQUEST, value, index, data);
int request = (mDeviceType == DeviceType.DEVICE_TYPE_HXN) ? VENDOR_WRITE_HXN_REQUEST : VENDOR_WRITE_REQUEST;
outControlTransfer(VENDOR_OUT_REQTYPE, request, value, index, data);
}

private void resetDevice() throws IOException {
purgeHwBuffers(true, true);
}

private void ctrlOut(int request, int value, int index, byte[] data) throws IOException {
outControlTransfer(PROLIFIC_CTRL_OUT_REQTYPE, request, value, index, data);
outControlTransfer(CTRL_OUT_REQTYPE, request, value, index, data);
}

private boolean testHxStatus() {
try {
inControlTransfer(VENDOR_IN_REQTYPE, VENDOR_READ_REQUEST, 0x8080, 0, 1);
return true;
} catch(IOException ignored) {
return false;
}
}

private void doBlackMagic() throws IOException {
if (mDeviceType == DeviceType.DEVICE_TYPE_HXN)
return;
vendorIn(0x8484, 0, 1);
vendorOut(0x0404, 0, null);
vendorIn(0x8484, 0, 1);
Expand Down Expand Up @@ -199,12 +228,20 @@ private int getStatus() throws IOException {
if ((mReadStatusThread == null) && (mReadStatusException == null)) {
synchronized (mReadStatusThreadLock) {
if (mReadStatusThread == null) {
byte[] data = vendorIn(GET_CONTROL_REQUEST, 0, 1);
mStatus = 0;
if((data[0] & GET_CONTROL_FLAG_CTS) == 0) mStatus |= STATUS_FLAG_CTS;
if((data[0] & GET_CONTROL_FLAG_DSR) == 0) mStatus |= STATUS_FLAG_DSR;
if((data[0] & GET_CONTROL_FLAG_CD) == 0) mStatus |= STATUS_FLAG_CD;
if((data[0] & GET_CONTROL_FLAG_RI) == 0) mStatus |= STATUS_FLAG_RI;
if(mDeviceType == DeviceType.DEVICE_TYPE_HXN) {
byte[] data = vendorIn(GET_CONTROL_HXN_REQUEST, 0, 1);
if ((data[0] & GET_CONTROL_HXN_FLAG_CTS) == 0) mStatus |= STATUS_FLAG_CTS;
if ((data[0] & GET_CONTROL_HXN_FLAG_DSR) == 0) mStatus |= STATUS_FLAG_DSR;
if ((data[0] & GET_CONTROL_HXN_FLAG_CD) == 0) mStatus |= STATUS_FLAG_CD;
if ((data[0] & GET_CONTROL_HXN_FLAG_RI) == 0) mStatus |= STATUS_FLAG_RI;
} else {
byte[] data = vendorIn(GET_CONTROL_REQUEST, 0, 1);
if ((data[0] & GET_CONTROL_FLAG_CTS) == 0) mStatus |= STATUS_FLAG_CTS;
if ((data[0] & GET_CONTROL_FLAG_DSR) == 0) mStatus |= STATUS_FLAG_DSR;
if ((data[0] & GET_CONTROL_FLAG_CD) == 0) mStatus |= STATUS_FLAG_CD;
if ((data[0] & GET_CONTROL_FLAG_RI) == 0) mStatus |= STATUS_FLAG_RI;
}
//Log.d(TAG, "start control line status thread " + mStatus);
mReadStatusThread = new Thread(this::readStatusThreadFunction);
mReadStatusThread.setDaemon(true);
Expand Down Expand Up @@ -266,12 +303,14 @@ public void openInt(UsbDeviceConnection connection) throws IOException {
mDeviceType = DeviceType.DEVICE_TYPE_T; // TA
} else if(deviceVersion == 0x500) {
mDeviceType = DeviceType.DEVICE_TYPE_T; // TB
} else if(usbVersion == 0x200 && !testHxStatus()) {
mDeviceType = DeviceType.DEVICE_TYPE_HXN;
} else {
mDeviceType = DeviceType.DEVICE_TYPE_HX;
}
setControlLines(mControlLinesValue);
resetDevice();
doBlackMagic();
setControlLines(mControlLinesValue);
}

@Override
Expand Down Expand Up @@ -304,6 +343,9 @@ private int filterBaudRate(int baudRate) {
if (baudRate <= 0) {
throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
}
if (mDeviceType == DeviceType.DEVICE_TYPE_HXN) {
return baudRate;
}
for(int br : standardBaudRates) {
if (br == baudRate) {
return baudRate;
Expand Down Expand Up @@ -501,12 +543,17 @@ public EnumSet<ControlLine> getSupportedControlLines() throws IOException {

@Override
public void purgeHwBuffers(boolean purgeWriteBuffers, boolean purgeReadBuffers) throws IOException {
if (purgeWriteBuffers) {
vendorOut(FLUSH_RX_REQUEST, 0, null);
}

if (purgeReadBuffers) {
vendorOut(FLUSH_TX_REQUEST, 0, null);
if (mDeviceType == DeviceType.DEVICE_TYPE_HXN) {
int index = 0;
if(purgeWriteBuffers) index |= RESET_HXN_RX_PIPE;
if(purgeReadBuffers) index |= RESET_HXN_TX_PIPE;
if(index != 0)
vendorOut(RESET_HXN_REQUEST, index, null);
} else {
if (purgeWriteBuffers)
vendorOut(FLUSH_RX_REQUEST, 0, null);
if (purgeReadBuffers)
vendorOut(FLUSH_TX_REQUEST, 0, null);
}
}

Expand All @@ -519,7 +566,15 @@ public void setBreak(boolean value) throws IOException {
public static Map<Integer, int[]> getSupportedDevices() {
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
supportedDevices.put(UsbId.VENDOR_PROLIFIC,
new int[] { UsbId.PROLIFIC_PL2303, });
new int[] {
UsbId.PROLIFIC_PL2303,
UsbId.PROLIFIC_PL2303GC,
UsbId.PROLIFIC_PL2303GB,
UsbId.PROLIFIC_PL2303GT,
UsbId.PROLIFIC_PL2303GL,
UsbId.PROLIFIC_PL2303GE,
UsbId.PROLIFIC_PL2303GS,
});
return supportedDevices;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ public final class UsbId {
public static final int SILABS_CP2108 = 0xea71;

public static final int VENDOR_PROLIFIC = 0x067b;
public static final int PROLIFIC_PL2303 = 0x2303;
public static final int PROLIFIC_PL2303 = 0x2303; // device type 01, T, HX
public static final int PROLIFIC_PL2303GC = 0x23a3; // device type HXN
public static final int PROLIFIC_PL2303GB = 0x23b3; // "
public static final int PROLIFIC_PL2303GT = 0x23cd; // "
public static final int PROLIFIC_PL2303GL = 0x23e3; // "
public static final int PROLIFIC_PL2303GE = 0x23e3; // "
public static final int PROLIFIC_PL2303GS = 0x23f3; // "

public static final int VENDOR_QINHENG = 0x1a86;
public static final int QINHENG_CH340 = 0x7523;
Expand Down

0 comments on commit c82cd28

Please sign in to comment.