1
0
mirror of https://github.com/mik3y/usb-serial-for-android.git synced 2026-08-14 18:03:08 +00:00

improve write timeout handling

Return type of write() method changed to void. The return value was redundant before, as it always was the request length or an exception was thrown.

If timeout is reached, write() now throws a SerialTimeoutException with ex.bytesTransferred filled with known transferred bytes.

Added CommonUsbSerialPort.getReadEndpoint() and .getWriteEndpoint() to assist in setting the optimal write buffer size with port.setWriteBufferSize(port.getWriteEndpoint().getMaxPacketSize()).

By default the write buffer size is > MaxPacketSize and the Linux kernel splits writes in chunks. When the timeout occurs, it's unknown how many chunks have already been transferred and the exception typically stores 0. With optimal write buffer size, this value is known and stored in SerialTimeoutException, but due to more kernel round trips write() might take slightly longer().
This commit is contained in:
kai-morich
2021-01-31 20:01:12 +01:00
parent 85d0348844
commit f60414f8ec
5 changed files with 202 additions and 77 deletions
@@ -63,7 +63,19 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
public int getPortNumber() {
return mPortNumber;
}
/**
* Returns the write endpoint.
* @return write endpoint
*/
public UsbEndpoint getWriteEndpoint() { return mWriteEndpoint; }
/**
* Returns the read endpoint.
* @return read endpoint
*/
public UsbEndpoint getReadEndpoint() { return mReadEndpoint; }
/**
* Returns the device serial number
* @return serial number
@@ -191,39 +203,55 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
}
@Override
public int write(final byte[] src, final int timeout) throws IOException {
public void write(final byte[] src, final int timeout) throws IOException {
int offset = 0;
int requestTimeout = timeout;
if(mConnection == null) {
throw new IOException("Connection closed");
}
while (offset < src.length) {
final int writeLength;
final int amtWritten;
final int requestLength;
final int actualLength;
final int requestDuration;
synchronized (mWriteBufferLock) {
final byte[] writeBuffer;
writeLength = Math.min(src.length - offset, mWriteBuffer.length);
requestLength = Math.min(src.length - offset, mWriteBuffer.length);
if (offset == 0) {
writeBuffer = src;
} else {
// bulkTransfer does not support offsets, make a copy.
System.arraycopy(src, offset, mWriteBuffer, 0, writeLength);
System.arraycopy(src, offset, mWriteBuffer, 0, requestLength);
writeBuffer = mWriteBuffer;
}
amtWritten = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, writeLength, timeout);
if (requestTimeout < 0) {
actualLength = -2;
requestDuration = 0;
} else {
final long startTime = System.currentTimeMillis();
actualLength = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, requestLength, requestTimeout);
requestDuration = (int) (System.currentTimeMillis() - startTime);
}
}
if (amtWritten <= 0) {
throw new IOException("Error writing " + writeLength
+ " bytes at offset " + offset + " length=" + src.length);
Log.d(TAG, "Wrote " + actualLength + "/" + requestLength + " offset " + offset + "/" + src.length + " timeout " + requestTimeout);
if (requestTimeout > 0) {
requestTimeout -= requestDuration;
if (requestTimeout == 0)
requestTimeout = -1;
}
Log.d(TAG, "Wrote amt=" + amtWritten + " attempted=" + writeLength);
offset += amtWritten;
if (actualLength <= 0) {
if(requestTimeout < 0) {
SerialTimeoutException ex = new SerialTimeoutException("Error writing " + requestLength + " bytes at offset " + offset + " of total " + src.length);
ex.bytesTransferred = offset;
throw ex;
} else {
throw new IOException("Error writing " + requestLength + " bytes at offset " + offset + " of total " + src.length);
}
}
offset += actualLength;
}
return offset;
}
@Override
@@ -0,0 +1,15 @@
package com.hoho.android.usbserial.driver;
import java.io.InterruptedIOException;
/**
* Signals that a timeout has occurred on serial write.
* Similar to SocketTimeoutException.
*
* {@see InterruptedIOException#bytesTransferred} may contain bytes transferred
*/
public class SerialTimeoutException extends InterruptedIOException {
public SerialTimeoutException(String s) {
super(s);
}
}
@@ -114,10 +114,11 @@ public interface UsbSerialPort extends Closeable {
*
* @param src the source byte buffer
* @param timeout the timeout for writing in milliseconds, 0 is infinite
* @return the actual number of bytes written
* @throws SerialTimeoutException if timeout reached before sending all data.
* ex.bytesTransferred may contain bytes transferred
* @throws IOException if an error occurred during writing
*/
int write(final byte[] src, final int timeout) throws IOException;
void write(final byte[] src, final int timeout) throws IOException;
/**
* Sets various serial port parameters.