Always use async read, as bulkTransfer can cause data loss. Increase API version to 17 because async read only works reliably since Android 4.2 (http://b.android.com/28023)
This commit is contained in:
parent
e527afdf35
commit
0d48ed04e7
|
@ -3,7 +3,7 @@
|
|||
This is a driver library for communication with Arduinos and other USB serial hardware on
|
||||
Android, using the
|
||||
[Android USB Host API](http://developer.android.com/guide/topics/connectivity/usb/host.html)
|
||||
available on Android 3.1+.
|
||||
available since Android 3.1 and asynchronous interrupt transfer working reliably since Android 4.2
|
||||
|
||||
No root access, ADK, or special kernel drivers are required; all drivers are implemented in
|
||||
Java. You get a raw serial port with `read()`, `write()`, and other basic
|
||||
|
|
|
@ -6,7 +6,7 @@ buildscript {
|
|||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.2.1'
|
||||
classpath 'com.android.tools.build:gradle:3.3.0'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#Sun Nov 11 09:16:07 CET 2018
|
||||
#Sun Feb 03 09:37:03 CET 2019
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
|
||||
|
|
|
@ -5,7 +5,7 @@ android {
|
|||
buildToolsVersion '28.0.3'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
minSdkVersion 17
|
||||
targetSdkVersion 28
|
||||
|
||||
testInstrumentationRunner "android.test.InstrumentationTestRunner"
|
||||
|
|
|
@ -7,7 +7,7 @@ android {
|
|||
buildToolsVersion '28.0.3'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
minSdkVersion 17
|
||||
targetSdkVersion 28
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ import android.hardware.usb.UsbDeviceConnection;
|
|||
import android.hardware.usb.UsbEndpoint;
|
||||
import android.hardware.usb.UsbInterface;
|
||||
import android.hardware.usb.UsbRequest;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -69,7 +68,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||
|
||||
class CdcAcmSerialPort extends CommonUsbSerialPort {
|
||||
|
||||
private final boolean mEnableAsyncReads;
|
||||
private UsbInterface mControlInterface;
|
||||
private UsbInterface mDataInterface;
|
||||
|
||||
|
@ -92,7 +90,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||
|
||||
public CdcAcmSerialPort(UsbDevice device, int portNumber) {
|
||||
super(device, portNumber);
|
||||
mEnableAsyncReads = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -118,13 +115,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||
openInterface();
|
||||
}
|
||||
|
||||
if (mEnableAsyncReads) {
|
||||
Log.d(TAG, "Async reads enabled");
|
||||
} else {
|
||||
Log.d(TAG, "Async reads disabled.");
|
||||
}
|
||||
|
||||
|
||||
opened = true;
|
||||
} finally {
|
||||
if (!opened) {
|
||||
|
@ -269,7 +259,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||
|
||||
@Override
|
||||
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
||||
if (mEnableAsyncReads) {
|
||||
final UsbRequest request = new UsbRequest();
|
||||
try {
|
||||
request.initialize(mConnection, mReadEndpoint);
|
||||
|
@ -295,27 +284,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
}
|
||||
|
||||
final int numBytesRead;
|
||||
synchronized (mReadBufferLock) {
|
||||
int readAmt = Math.min(dest.length, mReadBuffer.length);
|
||||
numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
|
||||
timeoutMillis);
|
||||
if (numBytesRead < 0) {
|
||||
// This sucks: we get -1 on timeout, not 0 as preferred.
|
||||
// We *should* use UsbRequest, except it has a bug/api oversight
|
||||
// where there is no way to determine the number of bytes read
|
||||
// in response :\ -- http://b.android.com/28023
|
||||
if (timeoutMillis == Integer.MAX_VALUE) {
|
||||
// Hack: Special case "~infinite timeout" as an error.
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
|
||||
}
|
||||
return numBytesRead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int write(byte[] src, int timeoutMillis) throws IOException {
|
||||
// TODO(mikey): Nearly identical to FtdiSerial write. Refactor.
|
||||
|
|
|
@ -26,7 +26,6 @@ import android.hardware.usb.UsbDeviceConnection;
|
|||
import android.hardware.usb.UsbEndpoint;
|
||||
import android.hardware.usb.UsbInterface;
|
||||
import android.hardware.usb.UsbRequest;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -84,14 +83,12 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
|
|||
private boolean dtr = false;
|
||||
private boolean rts = false;
|
||||
|
||||
private final Boolean mEnableAsyncReads;
|
||||
private UsbEndpoint mReadEndpoint;
|
||||
private UsbEndpoint mWriteEndpoint;
|
||||
private UsbRequest mUsbRequest;
|
||||
|
||||
public Ch340SerialPort(UsbDevice device, int portNumber) {
|
||||
super(device, portNumber);
|
||||
mEnableAsyncReads = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -127,12 +124,6 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
}
|
||||
|
||||
if (mEnableAsyncReads) {
|
||||
Log.d(TAG, "Async reads enabled");
|
||||
} else {
|
||||
Log.d(TAG, "Async reads disabled.");
|
||||
}
|
||||
|
||||
initialize();
|
||||
setBaudRate(DEFAULT_BAUD_RATE);
|
||||
|
||||
|
@ -153,12 +144,10 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
|
|||
if (mConnection == null) {
|
||||
throw new IOException("Already closed");
|
||||
}
|
||||
synchronized (mEnableAsyncReads) {
|
||||
synchronized (this) {
|
||||
if (mUsbRequest != null)
|
||||
mUsbRequest.cancel();
|
||||
}
|
||||
// TODO: nothing sended on close, maybe needed?
|
||||
|
||||
try {
|
||||
mConnection.close();
|
||||
} finally {
|
||||
|
@ -169,7 +158,6 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
|
|||
|
||||
@Override
|
||||
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
||||
if (mEnableAsyncReads) {
|
||||
final UsbRequest request = new UsbRequest();
|
||||
try {
|
||||
request.initialize(mConnection, mReadEndpoint);
|
||||
|
@ -179,7 +167,7 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
mUsbRequest = request;
|
||||
final UsbRequest response = mConnection.requestWait();
|
||||
synchronized (mEnableAsyncReads) {
|
||||
synchronized (this) {
|
||||
mUsbRequest = null;
|
||||
}
|
||||
if (response == null) {
|
||||
|
@ -197,23 +185,6 @@ public class Ch34xSerialDriver implements UsbSerialDriver {
|
|||
mUsbRequest = null;
|
||||
request.close();
|
||||
}
|
||||
} else {
|
||||
final int numBytesRead;
|
||||
synchronized (mReadBufferLock) {
|
||||
int readAmt = Math.min(dest.length, mReadBuffer.length);
|
||||
numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
|
||||
timeoutMillis);
|
||||
if (numBytesRead < 0) {
|
||||
// This sucks: we get -1 on timeout, not 0 as preferred.
|
||||
// We *should* use UsbRequest, except it has a bug/api oversight
|
||||
// where there is no way to determine the number of bytes read
|
||||
// in response :\ -- http://b.android.com/28023
|
||||
return 0;
|
||||
}
|
||||
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
|
||||
}
|
||||
return numBytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -27,7 +27,6 @@ import android.hardware.usb.UsbDeviceConnection;
|
|||
import android.hardware.usb.UsbEndpoint;
|
||||
import android.hardware.usb.UsbInterface;
|
||||
import android.hardware.usb.UsbRequest;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -107,7 +106,6 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||
private static final int CONTROL_WRITE_DTR = 0x0100;
|
||||
private static final int CONTROL_WRITE_RTS = 0x0200;
|
||||
|
||||
private final Boolean mEnableAsyncReads;
|
||||
private UsbEndpoint mReadEndpoint;
|
||||
private UsbEndpoint mWriteEndpoint;
|
||||
private UsbRequest mUsbRequest;
|
||||
|
@ -118,7 +116,6 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||
|
||||
public Cp21xxSerialPort(UsbDevice device, int portNumber) {
|
||||
super(device, portNumber);
|
||||
mEnableAsyncReads = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -180,13 +177,16 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||
if (mConnection == null) {
|
||||
throw new IOException("Already closed");
|
||||
}
|
||||
synchronized (mEnableAsyncReads) {
|
||||
synchronized (this) {
|
||||
if(mUsbRequest != null) {
|
||||
mUsbRequest.cancel();
|
||||
}
|
||||
}
|
||||
try {
|
||||
setConfigSingle(SILABSER_IFC_ENABLE_REQUEST_CODE, UART_DISABLE);
|
||||
} catch (Exception ignored)
|
||||
{}
|
||||
try {
|
||||
mConnection.close();
|
||||
} finally {
|
||||
mConnection = null;
|
||||
|
@ -195,7 +195,6 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||
|
||||
@Override
|
||||
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
||||
if (mEnableAsyncReads) {
|
||||
final UsbRequest request = new UsbRequest();
|
||||
try {
|
||||
request.initialize(mConnection, mReadEndpoint);
|
||||
|
@ -205,7 +204,7 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
mUsbRequest = request;
|
||||
final UsbRequest response = mConnection.requestWait();
|
||||
synchronized (mEnableAsyncReads) {
|
||||
synchronized (this) {
|
||||
mUsbRequest = null;
|
||||
}
|
||||
if (response == null) {
|
||||
|
@ -223,23 +222,6 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||
mUsbRequest = null;
|
||||
request.close();
|
||||
}
|
||||
} else {
|
||||
final int numBytesRead;
|
||||
synchronized (mReadBufferLock) {
|
||||
int readAmt = Math.min(dest.length, mReadBuffer.length);
|
||||
numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer, readAmt,
|
||||
timeoutMillis);
|
||||
if (numBytesRead < 0) {
|
||||
// This sucks: we get -1 on timeout, not 0 as preferred.
|
||||
// We *should* use UsbRequest, except it has a bug/api oversight
|
||||
// where there is no way to determine the number of bytes read
|
||||
// in response :\ -- http://b.android.com/28023
|
||||
return 0;
|
||||
}
|
||||
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
|
||||
}
|
||||
return numBytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -26,7 +26,6 @@ import android.hardware.usb.UsbDevice;
|
|||
import android.hardware.usb.UsbDeviceConnection;
|
||||
import android.hardware.usb.UsbEndpoint;
|
||||
import android.hardware.usb.UsbRequest;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -186,16 +185,8 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||
|
||||
private int mIndex = 0;
|
||||
|
||||
/**
|
||||
* Due to http://b.android.com/28023 , we cannot use UsbRequest async reads
|
||||
* since it gives no indication of number of bytes read. Set this to
|
||||
* {@code true} on platforms where it is fixed.
|
||||
*/
|
||||
private final boolean mEnableAsyncReads;
|
||||
|
||||
public FtdiSerialPort(UsbDevice device, int portNumber) {
|
||||
super(device, portNumber);
|
||||
mEnableAsyncReads = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -286,8 +277,6 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||
@Override
|
||||
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
||||
final UsbEndpoint endpoint = mDevice.getInterface(mPortNumber).getEndpoint(0);
|
||||
|
||||
if (mEnableAsyncReads) {
|
||||
final UsbRequest request = new UsbRequest();
|
||||
final ByteBuffer buf = ByteBuffer.wrap(dest);
|
||||
try {
|
||||
|
@ -310,22 +299,6 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
|
||||
return filterStatusBytes(dest, dest, totalBytesRead, endpoint.getMaxPacketSize());
|
||||
|
||||
} else {
|
||||
final int totalBytesRead;
|
||||
|
||||
synchronized (mReadBufferLock) {
|
||||
final int readAmt = Math.min(dest.length, mReadBuffer.length);
|
||||
totalBytesRead = mConnection.bulkTransfer(endpoint, mReadBuffer,
|
||||
readAmt, timeoutMillis);
|
||||
|
||||
if (totalBytesRead < MODEM_STATUS_HEADER_LENGTH) {
|
||||
throw new IOException("Expected at least " + MODEM_STATUS_HEADER_LENGTH + " bytes");
|
||||
}
|
||||
|
||||
return filterStatusBytes(mReadBuffer, dest, totalBytesRead, endpoint.getMaxPacketSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -33,7 +33,6 @@ import android.hardware.usb.UsbDeviceConnection;
|
|||
import android.hardware.usb.UsbEndpoint;
|
||||
import android.hardware.usb.UsbInterface;
|
||||
import android.hardware.usb.UsbRequest;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -112,7 +111,6 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
|
||||
private int mDeviceType = DEVICE_TYPE_HX;
|
||||
|
||||
private final boolean mEnableAsyncReads;
|
||||
private UsbEndpoint mReadEndpoint;
|
||||
private UsbEndpoint mWriteEndpoint;
|
||||
private UsbEndpoint mInterruptEndpoint;
|
||||
|
@ -130,7 +128,6 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
|
||||
public ProlificSerialPort(UsbDevice device, int portNumber) {
|
||||
super(device, portNumber);
|
||||
mEnableAsyncReads = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -373,7 +370,6 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
|
||||
@Override
|
||||
public int read(byte[] dest, int timeoutMillis) throws IOException {
|
||||
if (mEnableAsyncReads) {
|
||||
final UsbRequest request = new UsbRequest();
|
||||
try {
|
||||
request.initialize(mConnection, mReadEndpoint);
|
||||
|
@ -397,18 +393,6 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
} finally {
|
||||
request.close();
|
||||
}
|
||||
} else {
|
||||
synchronized (mReadBufferLock) {
|
||||
int readAmt = Math.min(dest.length, mReadBuffer.length);
|
||||
int numBytesRead = mConnection.bulkTransfer(mReadEndpoint, mReadBuffer,
|
||||
readAmt, timeoutMillis);
|
||||
if (numBytesRead < 0) {
|
||||
return 0;
|
||||
}
|
||||
System.arraycopy(mReadBuffer, 0, dest, 0, numBytesRead);
|
||||
return numBytesRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue