mirror of
https://github.com/mik3y/usb-serial-for-android
synced 2025-06-08 00:16:13 +00:00
improved error handling for read() with concurrent close() (#569)
- isOpen() returns false during concurrent close() - less tracing in SerialInputOutputManager
This commit is contained in:
parent
1245293888
commit
8b9ad7efdf
@ -13,7 +13,7 @@ android {
|
|||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
testInstrumentationRunnerArguments = [ // Raspi Windows LinuxVM ...
|
testInstrumentationRunnerArguments = [ // Raspi Windows LinuxVM ...
|
||||||
'rfc2217_server_host': '192.168.0.147',
|
'rfc2217_server_host': '192.168.0.78',
|
||||||
'rfc2217_server_nonstandard_baudrates': 'true', // true false false
|
'rfc2217_server_nonstandard_baudrates': 'true', // true false false
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -320,8 +320,10 @@ public class DeviceTest {
|
|||||||
try {
|
try {
|
||||||
closer.wait = false;
|
closer.wait = false;
|
||||||
usb.serialPort.read(new byte[256], 2000);
|
usb.serialPort.read(new byte[256], 2000);
|
||||||
|
|
||||||
fail("closed expected");
|
fail("closed expected");
|
||||||
} catch(IOException ex) {
|
} catch(IOException ex) {
|
||||||
|
assertFalse(usb.serialPort.isOpen());
|
||||||
assertEquals("Connection closed", ex.getMessage());
|
assertEquals("Connection closed", ex.getMessage());
|
||||||
}
|
}
|
||||||
th.join();
|
th.join();
|
||||||
@ -333,6 +335,7 @@ public class DeviceTest {
|
|||||||
usb.serialPort.read(new byte[256], 0);
|
usb.serialPort.read(new byte[256], 0);
|
||||||
fail("closed expected");
|
fail("closed expected");
|
||||||
} catch(IOException ex) {
|
} catch(IOException ex) {
|
||||||
|
assertFalse(usb.serialPort.isOpen());
|
||||||
assertEquals("Connection closed", ex.getMessage());
|
assertEquals("Connection closed", ex.getMessage());
|
||||||
}
|
}
|
||||||
th.join();
|
th.join();
|
||||||
|
@ -139,6 +139,8 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||||||
if (mConnection == null) {
|
if (mConnection == null) {
|
||||||
throw new IOException("Already closed");
|
throw new IOException("Already closed");
|
||||||
}
|
}
|
||||||
|
UsbDeviceConnection connection = mConnection;
|
||||||
|
mConnection = null;
|
||||||
try {
|
try {
|
||||||
mUsbRequest.cancel();
|
mUsbRequest.cancel();
|
||||||
} catch(Exception ignored) {}
|
} catch(Exception ignored) {}
|
||||||
@ -147,9 +149,8 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||||||
closeInt();
|
closeInt();
|
||||||
} catch(Exception ignored) {}
|
} catch(Exception ignored) {}
|
||||||
try {
|
try {
|
||||||
mConnection.close();
|
connection.close();
|
||||||
} catch(Exception ignored) {}
|
} catch(Exception ignored) {}
|
||||||
mConnection = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void closeInt();
|
protected abstract void closeInt();
|
||||||
@ -157,10 +158,13 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||||||
/**
|
/**
|
||||||
* use simple USB request supported by all devices to test if connection is still valid
|
* use simple USB request supported by all devices to test if connection is still valid
|
||||||
*/
|
*/
|
||||||
protected void testConnection() throws IOException {
|
protected void testConnection(boolean full) throws IOException {
|
||||||
if(mConnection == null || mUsbRequest == null) {
|
if(mConnection == null) {
|
||||||
throw new IOException("Connection closed");
|
throw new IOException("Connection closed");
|
||||||
}
|
}
|
||||||
|
if(!full) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
byte[] buf = new byte[2];
|
byte[] buf = new byte[2];
|
||||||
int len = mConnection.controlTransfer(0x80 /*DEVICE*/, 0 /*GET_STATUS*/, 0, 0, buf, buf.length, 200);
|
int len = mConnection.controlTransfer(0x80 /*DEVICE*/, 0 /*GET_STATUS*/, 0, 0, buf, buf.length, 200);
|
||||||
if(len < 0)
|
if(len < 0)
|
||||||
@ -169,7 +173,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||||||
|
|
||||||
@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 <= 0) {
|
if(dest.length == 0) {
|
||||||
throw new IllegalArgumentException("Read buffer too small");
|
throw new IllegalArgumentException("Read buffer too small");
|
||||||
}
|
}
|
||||||
return read(dest, dest.length, timeout);
|
return read(dest, dest.length, timeout);
|
||||||
@ -179,7 +183,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||||||
public int read(final byte[] dest, final int length, final int timeout) throws IOException {return read(dest, length, timeout, true);}
|
public int read(final byte[] dest, final int length, final int timeout) throws IOException {return read(dest, length, timeout, true);}
|
||||||
|
|
||||||
protected int read(final byte[] dest, int length, final int timeout, boolean testConnection) throws IOException {
|
protected int read(final byte[] dest, int length, final int timeout, boolean testConnection) throws IOException {
|
||||||
if(mConnection == null || mUsbRequest == null) {
|
if(mConnection == null) {
|
||||||
throw new IOException("Connection closed");
|
throw new IOException("Connection closed");
|
||||||
}
|
}
|
||||||
if(length <= 0) {
|
if(length <= 0) {
|
||||||
@ -201,8 +205,8 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||||||
nread = mConnection.bulkTransfer(mReadEndpoint, dest, readMax, timeout);
|
nread = mConnection.bulkTransfer(mReadEndpoint, dest, readMax, timeout);
|
||||||
// Android error propagation is improvable:
|
// Android error propagation is improvable:
|
||||||
// nread == -1 can be: timeout, connection lost, buffer to small, ???
|
// nread == -1 can be: timeout, connection lost, buffer to small, ???
|
||||||
if(nread == -1 && testConnection && MonotonicClock.millis() < endTime)
|
if(nread == -1 && testConnection)
|
||||||
testConnection();
|
testConnection(MonotonicClock.millis() < endTime);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
final ByteBuffer buf = ByteBuffer.wrap(dest, 0, length);
|
final ByteBuffer buf = ByteBuffer.wrap(dest, 0, length);
|
||||||
@ -217,7 +221,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||||||
// Android error propagation is improvable:
|
// Android error propagation is improvable:
|
||||||
// response != null & nread == 0 can be: connection lost, buffer to small, ???
|
// response != null & nread == 0 can be: connection lost, buffer to small, ???
|
||||||
if(nread == 0) {
|
if(nread == 0) {
|
||||||
testConnection();
|
testConnection(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Math.max(nread, 0);
|
return Math.max(nread, 0);
|
||||||
|
@ -165,8 +165,8 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||||||
do {
|
do {
|
||||||
nread = super.read(dest, length, Math.max(1, (int)(endTime - MonotonicClock.millis())), false);
|
nread = super.read(dest, length, Math.max(1, (int)(endTime - MonotonicClock.millis())), false);
|
||||||
} while (nread == READ_HEADER_LENGTH && MonotonicClock.millis() < endTime);
|
} while (nread == READ_HEADER_LENGTH && MonotonicClock.millis() < endTime);
|
||||||
if(nread <= 0 && MonotonicClock.millis() < endTime)
|
if(nread <= 0)
|
||||||
testConnection();
|
testConnection(MonotonicClock.millis() < endTime);
|
||||||
} else {
|
} else {
|
||||||
do {
|
do {
|
||||||
nread = super.read(dest, length, timeout);
|
nread = super.read(dest, length, timeout);
|
||||||
|
@ -205,8 +205,8 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||||||
byte[] buffer = new byte[STATUS_BUFFER_SIZE];
|
byte[] buffer = new byte[STATUS_BUFFER_SIZE];
|
||||||
long endTime = MonotonicClock.millis() + 500;
|
long endTime = MonotonicClock.millis() + 500;
|
||||||
int readBytesCount = mConnection.bulkTransfer(mInterruptEndpoint, buffer, STATUS_BUFFER_SIZE, 500);
|
int readBytesCount = mConnection.bulkTransfer(mInterruptEndpoint, buffer, STATUS_BUFFER_SIZE, 500);
|
||||||
if(readBytesCount == -1 && MonotonicClock.millis() < endTime)
|
if(readBytesCount == -1)
|
||||||
testConnection();
|
testConnection(MonotonicClock.millis() < endTime);
|
||||||
if (readBytesCount > 0) {
|
if (readBytesCount > 0) {
|
||||||
if (readBytesCount != STATUS_BUFFER_SIZE) {
|
if (readBytesCount != STATUS_BUFFER_SIZE) {
|
||||||
throw new IOException("Invalid status notification, expected " + STATUS_BUFFER_SIZE + " bytes, got " + readBytesCount);
|
throw new IOException("Invalid status notification, expected " + STATUS_BUFFER_SIZE + " bytes, got " + readBytesCount);
|
||||||
|
@ -203,7 +203,11 @@ public class SerialInputOutputManager implements Runnable {
|
|||||||
step();
|
step();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
if(mSerialPort.isOpen()) {
|
||||||
Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e);
|
Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e);
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "Socket closed");
|
||||||
|
}
|
||||||
final Listener listener = getListener();
|
final Listener listener = getListener();
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.onRunError(e);
|
listener.onRunError(e);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user