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

read with timeout now throws error on connection lost, e.g. device disconnected

and similar connection lost detection for prolific input control lines
This commit is contained in:
kai-morich 2020-09-06 19:58:18 +02:00
parent c53c3ed0ae
commit 26999e3626
4 changed files with 43 additions and 13 deletions

View File

@ -1660,18 +1660,27 @@ public class DeviceTest {
purged = false; purged = false;
} }
usb.deviceConnection.close(); usb.deviceConnection.close();
try { try { // only Prolific driver has early exit if nothing changed
usb.setParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); usb.setParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE);
if(!(usb.serialDriver instanceof ProlificSerialDriver)) if(!(usb.serialDriver instanceof ProlificSerialDriver))
fail("setParameters error expected"); fail("setParameters error expected");
} catch (IOException ignored) { } catch (IOException ignored) {
} }
try {
usb.setParameters(57600, 8, 1, UsbSerialPort.PARITY_NONE);
fail("setParameters error expected");
} catch (IOException ignored) {
}
try { try {
usb.write("x".getBytes()); usb.write("x".getBytes());
fail("write error expected"); fail("write error expected");
} catch (IOException ignored) { } catch (IOException ignored) {
} }
usb.serialPort.read(buf, 1000); // bulkTransfer returns -1 on timeout and error, so no exception thrown here try {
usb.serialPort.read(buf, 1000);
fail("read error expected");
} catch (IOException ignored) {
}
try { try {
usb.serialPort.read(buf, 0); usb.serialPort.read(buf, 0);
fail("read error expected"); fail("read error expected");
@ -1683,16 +1692,17 @@ public class DeviceTest {
} catch (IOException ignored) { } catch (IOException ignored) {
} }
try { try {
if(usb.serialDriver instanceof ProlificSerialDriver)
Thread.sleep(600); // wait for background thread
usb.serialPort.getRI(); usb.serialPort.getRI();
if(!(usb.serialDriver instanceof ProlificSerialDriver)) fail("getRI error expected");
fail("getRI error expected");
} catch (IOException ignored) { } catch (IOException ignored) {
} catch (UnsupportedOperationException ignored) { } catch (UnsupportedOperationException ignored) {
} }
if(purged) { if(purged) {
try { try {
usb.serialPort.purgeHwBuffers(true, true); usb.serialPort.purgeHwBuffers(true, true);
fail("setRts error expected"); fail("purgeHwBuffers error expected");
} catch (IOException ignored) { } catch (IOException ignored) {
} }
} }

View File

@ -129,13 +129,27 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
protected abstract void closeInt(); protected abstract void closeInt();
/**
* use simple USB request supported by all devices to test if connection is still valid
*/
protected void testConnection() throws IOException {
byte[] buf = new byte[2];
int len = mConnection.controlTransfer(0x80 /*DEVICE*/, 0 /*GET_STATUS*/, 0, 0, buf, buf.length, 200);
if(len < 0)
throw new IOException("USB get_status request failed");
}
@Override @Override
public int read(final byte[] dest, final int timeout) throws IOException { public int read(final byte[] dest, final int timeout) throws IOException {
return read(dest, timeout, true);
}
protected int read(final byte[] dest, final int timeout, boolean testConnection) throws IOException {
if(mConnection == null) { if(mConnection == null) {
throw new IOException("Connection closed"); throw new IOException("Connection closed");
} }
if(dest.length <= 0) { if(dest.length <= 0) {
throw new IllegalArgumentException("read buffer to small"); throw new IllegalArgumentException("Read buffer to small");
} }
final int nread; final int nread;
if (timeout != 0) { if (timeout != 0) {
@ -147,8 +161,12 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
// /system/lib64/libusbhost.so (usb_request_wait+192) // /system/lib64/libusbhost.so (usb_request_wait+192)
// /system/lib64/libandroid_runtime.so (android_hardware_UsbDeviceConnection_request_wait(_JNIEnv*, _jobject*, long)+84) // /system/lib64/libandroid_runtime.so (android_hardware_UsbDeviceConnection_request_wait(_JNIEnv*, _jobject*, long)+84)
// data loss / crashes were observed with timeout up to 200 msec // data loss / crashes were observed with timeout up to 200 msec
long endTime = testConnection ? System.currentTimeMillis() + timeout : 0;
int readMax = Math.min(dest.length, MAX_READ_SIZE); int readMax = Math.min(dest.length, MAX_READ_SIZE);
nread = mConnection.bulkTransfer(mReadEndpoint, dest, readMax, timeout); nread = mConnection.bulkTransfer(mReadEndpoint, dest, readMax, timeout);
// Android error propagation is improvable, nread == -1 can be: timeout, connection lost, buffer undersized, ...
if(nread == -1 && testConnection && System.currentTimeMillis() < endTime)
testConnection();
} else { } else {
final ByteBuffer buf = ByteBuffer.wrap(dest); final ByteBuffer buf = ByteBuffer.wrap(dest);

View File

@ -138,7 +138,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
@Override @Override
public int read(final byte[] dest, final int timeout) throws IOException { public int read(final byte[] dest, final int timeout) throws IOException {
if(dest.length <= READ_HEADER_LENGTH) { if(dest.length <= READ_HEADER_LENGTH) {
throw new IllegalArgumentException("read buffer to small"); throw new IllegalArgumentException("Read buffer to small");
// could allocate larger buffer, including space for 2 header bytes, but this would // could allocate larger buffer, including space for 2 header bytes, but this would
// result in buffers not being 64 byte aligned any more, causing data loss at continuous // result in buffers not being 64 byte aligned any more, causing data loss at continuous
// data transfer at high baud rates when buffers are fully filled. // data transfer at high baud rates when buffers are fully filled.
@ -147,11 +147,13 @@ public class FtdiSerialDriver implements UsbSerialDriver {
if (timeout != 0) { if (timeout != 0) {
long endTime = System.currentTimeMillis() + timeout; long endTime = System.currentTimeMillis() + timeout;
do { do {
nread = super.read(dest, Math.max(1, (int)(endTime - System.currentTimeMillis()))); nread = super.read(dest, Math.max(1, (int)(endTime - System.currentTimeMillis())), false);
} while (nread == READ_HEADER_LENGTH && System.currentTimeMillis() < endTime); } while (nread == READ_HEADER_LENGTH && System.currentTimeMillis() < endTime);
if(nread <= 0 && System.currentTimeMillis() < endTime)
testConnection();
} else { } else {
do { do {
nread = super.read(dest, timeout); nread = super.read(dest, timeout, false);
} while (nread == READ_HEADER_LENGTH); } while (nread == READ_HEADER_LENGTH);
} }
return readFilter(dest, nread); return readFilter(dest, nread);

View File

@ -184,10 +184,10 @@ public class ProlificSerialDriver implements UsbSerialDriver {
try { try {
while (!mStopReadStatusThread) { while (!mStopReadStatusThread) {
byte[] buffer = new byte[STATUS_BUFFER_SIZE]; byte[] buffer = new byte[STATUS_BUFFER_SIZE];
int readBytesCount = mConnection.bulkTransfer(mInterruptEndpoint, long endTime = System.currentTimeMillis() + 500;
buffer, int readBytesCount = mConnection.bulkTransfer(mInterruptEndpoint, buffer, STATUS_BUFFER_SIZE, 500);
STATUS_BUFFER_SIZE, if(readBytesCount == -1 && System.currentTimeMillis() < endTime)
500); testConnection();
if (readBytesCount > 0) { if (readBytesCount > 0) {
if (readBytesCount == STATUS_BUFFER_SIZE) { if (readBytesCount == STATUS_BUFFER_SIZE) {
mStatus = buffer[STATUS_BYTE_IDX] & 0xff; mStatus = buffer[STATUS_BYTE_IDX] & 0xff;