Skip to content

Commit 7fed2ad

Browse files
authored
feat: implemented serial driver to facilitate communication with PSLab Devices (#2488)
1 parent aba3806 commit 7fed2ad

File tree

3 files changed

+97
-167
lines changed

3 files changed

+97
-167
lines changed

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ dependencies {
7676
implementation("de.hdodenhof:circleimageview:3.1.0")
7777
implementation("com.github.devlight.navigationtabstrip:navigationtabstrip:1.0.4")
7878
implementation("com.afollestad.material-dialogs", "commons", "0.9.6.0")
79+
implementation("com.github.mik3y:usb-serial-for-android:3.7.3")
7980
implementation("com.github.medyo:android-about-page:1.3.1")
8081
implementation("com.github.tiagohm.MarkdownView:library:0.19.0")
8182
implementation("com.github.mirrajabi:search-dialog:1.2.4")
Lines changed: 64 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,57 @@
11
package io.pslab.communication;
22

3-
import android.hardware.usb.UsbConstants;
43
import android.hardware.usb.UsbDevice;
54
import android.hardware.usb.UsbDeviceConnection;
6-
import android.hardware.usb.UsbEndpoint;
7-
import android.hardware.usb.UsbInterface;
85
import android.hardware.usb.UsbManager;
9-
import android.os.Build;
10-
import android.os.SystemClock;
116
import android.util.Log;
127

8+
import com.hoho.android.usbserial.driver.CdcAcmSerialDriver;
9+
import com.hoho.android.usbserial.driver.Cp21xxSerialDriver;
10+
import com.hoho.android.usbserial.driver.ProbeTable;
11+
import com.hoho.android.usbserial.driver.UsbSerialDriver;
12+
import com.hoho.android.usbserial.driver.UsbSerialPort;
13+
import com.hoho.android.usbserial.driver.UsbSerialProber;
14+
1315
import java.io.IOException;
16+
import java.util.List;
1417

1518
public class CommunicationHandler {
16-
1719
private final String TAG = this.getClass().getSimpleName();
18-
private static final int PSLAB_VENDOR_ID = 1240;
19-
private static final int PSLAB_PRODUCT_ID = 223;
20-
21-
private UsbInterface mControlInterface;
22-
private UsbInterface mDataInterface;
23-
24-
private UsbEndpoint mControlEndpoint;
25-
private UsbEndpoint mReadEndpoint;
26-
private UsbEndpoint mWriteEndpoint;
27-
28-
private boolean mRts = false;
29-
private boolean mDtr = false;
20+
private static final int PSLAB_VENDOR_ID_V5 = 1240;
21+
private static final int PSLAB_PRODUCT_ID_V5 = 223;
22+
private static final int PSLAB_VENDOR_ID_V6 = 0x10C4;
23+
private static final int PSLAB_PRODUCT_ID_V6 = 0xEA60;
3024
private boolean connected = false, device_found = false;
31-
32-
private static final int USB_RECIP_INTERFACE = 0x01;
33-
private static final int USB_RT_ACM = UsbConstants.USB_TYPE_CLASS | USB_RECIP_INTERFACE;
34-
35-
private static final int SET_LINE_CODING = 0x20; // USB CDC 1.1 section 6.2
36-
private static final int GET_LINE_CODING = 0x21;
37-
private static final int SET_CONTROL_LINE_STATE = 0x22;
38-
private static final int SEND_BREAK = 0x23;
25+
private UsbManager mUsbManager;
26+
private UsbDeviceConnection mConnection;
27+
private UsbSerialDriver driver;
28+
private UsbSerialPort port;
29+
public UsbDevice mUsbDevice;
30+
List<UsbSerialDriver> drivers;
3931

4032
private static final int DEFAULT_READ_BUFFER_SIZE = 32 * 1024;
4133
private static final int DEFAULT_WRITE_BUFFER_SIZE = 32 * 1024;
4234

43-
public UsbDevice mUsbDevice = null;
44-
45-
protected final Object mReadBufferLock = new Object();
46-
protected final Object mWriteBufferLock = new Object();
47-
4835
private byte[] mReadBuffer;
4936
private byte[] mWriteBuffer;
5037

51-
private UsbDeviceConnection mConnection;
52-
53-
private UsbManager mUsbManager;
54-
5538
public CommunicationHandler(UsbManager usbManager) {
5639
this.mUsbManager = usbManager;
5740
mUsbDevice = null;
58-
for (final UsbDevice device : mUsbManager.getDeviceList().values()) {
59-
Log.d(TAG, "VID : " + device.getVendorId() + "PID : " + device.getProductId());
60-
if (device.getVendorId() == PSLAB_VENDOR_ID && device.getProductId() == PSLAB_PRODUCT_ID) {
61-
Log.d(TAG, "Found PSLAB Device");
62-
mUsbDevice = device;
63-
device_found = true;
64-
break;
65-
}
41+
ProbeTable customTable = new ProbeTable();
42+
customTable.addProduct(PSLAB_VENDOR_ID_V5, PSLAB_PRODUCT_ID_V5, CdcAcmSerialDriver.class);
43+
customTable.addProduct(PSLAB_VENDOR_ID_V6, PSLAB_PRODUCT_ID_V6, Cp21xxSerialDriver.class);
44+
45+
UsbSerialProber prober = new UsbSerialProber(customTable);
46+
drivers = prober.findAllDrivers(usbManager);
47+
48+
if (drivers.isEmpty()) {
49+
Log.d(TAG, "No drivers found");
50+
} else {
51+
Log.d(TAG, "Found PSLab device");
52+
device_found = true;
53+
driver = drivers.get(0);
54+
mUsbDevice = driver.getDevice();
6655
}
6756
mReadBuffer = new byte[DEFAULT_READ_BUFFER_SIZE];
6857
mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE];
@@ -73,33 +62,13 @@ public void open() throws IOException {
7362
throw new IOException("Device not Connected");
7463
}
7564
mConnection = mUsbManager.openDevice(mUsbDevice);
76-
Log.d(TAG, "Claiming interfaces, count=" + mUsbDevice.getInterfaceCount());
77-
mConnection.controlTransfer(0x21, 0x22, 0x1, 0, null, 0, 0);
78-
79-
mControlInterface = mUsbDevice.getInterface(0);
80-
Log.d(TAG, "Control interface=" + mControlInterface);
81-
82-
if (!mConnection.claimInterface(mControlInterface, true)) {
83-
throw new IOException("Could not claim control interface.");
84-
}
85-
86-
mControlEndpoint = mControlInterface.getEndpoint(0);
87-
Log.d(TAG, "Control endpoint direction: " + mControlEndpoint.getDirection());
88-
89-
Log.d(TAG, "Claiming data interface.");
90-
mDataInterface = mUsbDevice.getInterface(1);
91-
Log.d(TAG, "data interface=" + mDataInterface);
92-
93-
if (!mConnection.claimInterface(mDataInterface, true)) {
94-
throw new IOException("Could not claim data interface.");
65+
if (mConnection == null) {
66+
throw new IOException("Could not open device.");
9567
}
96-
mReadEndpoint = mDataInterface.getEndpoint(1);
97-
Log.d(TAG, "Read endpoint direction: " + mReadEndpoint.getDirection());
98-
mWriteEndpoint = mDataInterface.getEndpoint(0);
99-
Log.d(TAG, "Write endpoint direction: " + mWriteEndpoint.getDirection());
10068
connected = true;
101-
setBaudRate(1000000);
102-
//Thread.sleep(1000);
69+
port = driver.getPorts().get(0);
70+
port.open(mConnection);
71+
port.setParameters(1000000, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
10372
clear();
10473
}
10574

@@ -115,113 +84,60 @@ public void close() throws IOException {
11584
if (mConnection == null) {
11685
return;
11786
}
118-
mConnection.releaseInterface(mDataInterface);
119-
mConnection.releaseInterface(mControlInterface);
120-
mConnection.close();
87+
port.close();
12188
connected = false;
122-
mConnection = null;
12389
}
12490

12591
public int read(byte[] dest, int bytesToBeRead, int timeoutMillis) throws IOException {
92+
if (mUsbDevice.getProductId() == PSLAB_PRODUCT_ID_V5 && mUsbDevice.getVendorId() == PSLAB_VENDOR_ID_V5) {
93+
return readCdcAcm(dest, bytesToBeRead, timeoutMillis);
94+
}
12695
int numBytesRead = 0;
127-
//synchronized (mReadBufferLock) {
12896
int readNow;
12997
Log.v(TAG, "TO read : " + bytesToBeRead);
13098
int bytesToBeReadTemp = bytesToBeRead;
13199
while (numBytesRead < bytesToBeRead) {
132-
readNow = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, bytesToBeReadTemp, timeoutMillis);
133-
if (readNow < 0) {
100+
readNow = port.read(mReadBuffer, bytesToBeReadTemp, timeoutMillis);
101+
if (readNow == 0) {
134102
Log.e(TAG, "Read Error: " + bytesToBeReadTemp);
135103
return numBytesRead;
136104
} else {
137-
//Log.v(TAG, "Read something" + mReadBuffer);
138105
System.arraycopy(mReadBuffer, 0, dest, numBytesRead, readNow);
139106
numBytesRead += readNow;
140107
bytesToBeReadTemp -= readNow;
141-
//Log.v(TAG, "READ : " + numBytesRead);
142-
//Log.v(TAG, "REMAINING: " + bytesToBeRead);
143108
}
144109
}
145-
//}
146110
Log.v("Bytes Read", "" + numBytesRead);
147111
return numBytesRead;
148112
}
149113

150-
public int write(byte[] src, int timeoutMillis) throws IOException {
151-
if (Build.VERSION.SDK_INT < 18) {
152-
return writeSupportAPI(src, timeoutMillis);
153-
}
154-
int written = 0;
155-
while (written < src.length) {
156-
int writeLength, amtWritten;
157-
//synchronized (mWriteBufferLock) {
158-
writeLength = Math.min(mWriteBuffer.length, src.length - written);
159-
// bulk transfer supports offset from API 18
160-
amtWritten = mConnection.bulkTransfer(mWriteEndpoint, src, written, writeLength, timeoutMillis);
161-
//}
162-
if (amtWritten < 0) {
163-
throw new IOException("Error writing " + writeLength
164-
+ " bytes at offset " + written + " length=" + src.length);
165-
}
166-
written += amtWritten;
167-
}
168-
return written;
169-
}
170-
171-
172-
// For supporting devices with API version < 18
173-
private int writeSupportAPI(byte[] src, int timeoutMillis) throws IOException {
174-
int written = 0;
175-
while (written < src.length) {
176-
final int writeLength;
177-
final int amtWritten;
178-
//synchronized (mWriteBufferLock) {
179-
final byte[] writeBuffer;
180-
writeLength = Math.min(src.length - written, mWriteBuffer.length);
181-
if (written == 0) {
182-
writeBuffer = src;
114+
public int readCdcAcm(byte[] dest, int bytesToBeRead, int timeoutMillis) throws IOException {
115+
int numBytesRead = 0;
116+
int readNow;
117+
Log.v(TAG, "TO read : " + bytesToBeRead);
118+
int bytesToBeReadTemp = bytesToBeRead;
119+
while (numBytesRead < bytesToBeRead) {
120+
readNow = mConnection.bulkTransfer(mUsbDevice.getInterface(1).getEndpoint(1), mReadBuffer, bytesToBeReadTemp, timeoutMillis);
121+
if (readNow < 0) {
122+
Log.e(TAG, "Read Error: " + bytesToBeReadTemp);
123+
return numBytesRead;
183124
} else {
184-
// bulkTransfer does not support offsets for API level < 18, so make a copy.
185-
System.arraycopy(src, written, mWriteBuffer, 0, writeLength);
186-
writeBuffer = mWriteBuffer;
187-
}
188-
amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength, timeoutMillis);
189-
//}
190-
if (amtWritten <= 0) {
191-
throw new IOException("Error writing " + writeLength
192-
+ " bytes at offset " + written + " length=" + src.length);
125+
System.arraycopy(mReadBuffer, 0, dest, numBytesRead, readNow);
126+
numBytesRead += readNow;
127+
bytesToBeReadTemp -= readNow;
193128
}
194-
written += amtWritten;
195129
}
196-
return written;
197-
}
198-
199-
200-
private void clear() {
201-
mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, 100, 50);
202-
}
203-
204-
private void setBaudRate(int baudRate) {
205-
byte[] msg = {
206-
(byte) (baudRate & 0xff),
207-
(byte) ((baudRate >> 8) & 0xff),
208-
(byte) ((baudRate >> 16) & 0xff),
209-
(byte) ((baudRate >> 24) & 0xff),
210-
(byte) 0,
211-
(byte) 0,
212-
(byte) 8};
213-
sendAcmControlMessage(SET_LINE_CODING, 0, msg);
214-
SystemClock.sleep(100);
215-
clear();
130+
Log.v("Bytes Read", "" + numBytesRead);
131+
return numBytesRead;
216132
}
217133

218-
private int sendAcmControlMessage(int request, int value, byte[] buf) {
219-
return mConnection.controlTransfer(USB_RT_ACM, request, value, 0, buf, buf != null ? buf.length : 0, 5000);
134+
public void write(byte[] src, int timeoutMillis) throws IOException {
135+
int writeLength;
136+
writeLength = src.length;
137+
port.write(src, writeLength, timeoutMillis);
220138
}
221139

222-
public void setDtrRts() {
223-
int value = (mRts ? 0x2 : 0) | (mDtr ? 0x1 : 0);
224-
sendAcmControlMessage(SET_CONTROL_LINE_STATE, value, null);
140+
private void clear() throws IOException {
141+
port.read(mReadBuffer, 100, 50);
225142
}
226-
227143
}
Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,39 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources>
3-
<!-- For PSLab -->
4-
<usb-device vendor-id="1240" product-id="223" />
3+
<!-- 0x0403 / 0x60??: FTDI -->
4+
<usb-device vendor-id="1027" product-id="24577" /> <!-- 0x6001: FT232R -->
5+
<usb-device vendor-id="1027" product-id="24592" /> <!-- 0x6010: FT2232H -->
6+
<usb-device vendor-id="1027" product-id="24593" /> <!-- 0x6011: FT4232H -->
7+
<usb-device vendor-id="1027" product-id="24596" /> <!-- 0x6014: FT232H -->
8+
<usb-device vendor-id="1027" product-id="24597" /> <!-- 0x6015: FT230X, FT231X, FT234XD -->
59

6-
<!-- 0x0403 / 0x6001: FTDI FT232R UART -->
7-
<usb-device vendor-id="1027" product-id="24577" />
10+
<!-- 0x10C4 / 0xEA??: Silabs CP210x -->
11+
<usb-device vendor-id="4292" product-id="60000" /> <!-- 0xea60: CP2102 and other CP210x single port devices -->
12+
<usb-device vendor-id="4292" product-id="60016" /> <!-- 0xea70: CP2105 -->
13+
<usb-device vendor-id="4292" product-id="60017" /> <!-- 0xea71: CP2108 -->
814

9-
<!-- 0x0403 / 0x6015: FTDI FT231X -->
10-
<usb-device vendor-id="1027" product-id="24597" />
15+
<!-- 0x067B / 0x23?3: Prolific PL2303x -->
16+
<usb-device vendor-id="1659" product-id="8963" /> <!-- 0x2303: PL2303HX, HXD, TA, ... -->
17+
<usb-device vendor-id="1659" product-id="9123" /> <!-- 0x23a3: PL2303GC -->
18+
<usb-device vendor-id="1659" product-id="9139" /> <!-- 0x23b3: PL2303GB -->
19+
<usb-device vendor-id="1659" product-id="9155" /> <!-- 0x23c3: PL2303GT -->
20+
<usb-device vendor-id="1659" product-id="9171" /> <!-- 0x23d3: PL2303GL -->
21+
<usb-device vendor-id="1659" product-id="9187" /> <!-- 0x23e3: PL2303GE -->
22+
<usb-device vendor-id="1659" product-id="9203" /> <!-- 0x23f3: PL2303GS -->
1123

12-
<!-- 0x2341 / Arduino -->
13-
<usb-device vendor-id="9025" />
24+
<!-- 0x1a86 / 0x?523: Qinheng CH34x -->
25+
<usb-device vendor-id="6790" product-id="21795" /> <!-- 0x5523: CH341A -->
26+
<usb-device vendor-id="6790" product-id="29987" /> <!-- 0x7523: CH340 -->
1427

15-
<!-- 0x16C0 / 0x0483: Teensyduino -->
16-
<usb-device vendor-id="5824" product-id="1155" />
17-
18-
<!-- 0x10C4 / 0xEA60: CP210x UART Bridge -->
19-
<usb-device vendor-id="4292" product-id="60000" />
20-
21-
<!-- 0x067B / 0x2303: Prolific PL2303 -->
22-
<usb-device vendor-id="1659" product-id="8963" />
23-
24-
<!-- 0x1a86 / 0x7523: Qinheng CH340 -->
25-
<usb-device vendor-id="6790" product-id="29987" />
28+
<!-- CDC driver -->
29+
<usb-device vendor-id="1240" product-id="223"/> <!-- 1240 / 223: MCP2200(For PSLab V5) -->
30+
<usb-device vendor-id="9025" /> <!-- 0x2341 / ......: Arduino -->
31+
<usb-device vendor-id="5824" product-id="1155" /> <!-- 0x16C0 / 0x0483: Teensyduino -->
32+
<usb-device vendor-id="1003" product-id="8260" /> <!-- 0x03EB / 0x2044: Atmel Lufa -->
33+
<usb-device vendor-id="7855" product-id="4" /> <!-- 0x1eaf / 0x0004: Leaflabs Maple -->
34+
<usb-device vendor-id="3368" product-id="516" /> <!-- 0x0d28 / 0x0204: ARM mbed -->
35+
<usb-device vendor-id="1155" product-id="22336" /><!-- 0x0483 / 0x5740: ST CDC -->
36+
<usb-device vendor-id="11914" product-id="5" /> <!-- 0x2E8A / 0x0005: Raspberry Pi Pico Micropython -->
37+
<usb-device vendor-id="11914" product-id="10" /> <!-- 0x2E8A / 0x000A: Raspberry Pi Pico SDK -->
38+
<usb-device vendor-id="6790" product-id="21972" /><!-- 0x1A86 / 0x55D4: Qinheng CH9102F -->
2639
</resources>

0 commit comments

Comments
 (0)