mirror of
https://github.com/mik3y/usb-serial-for-android
synced 2025-06-07 16:06:10 +00:00
simplify write timeout handling
This commit is contained in:
parent
f60414f8ec
commit
4ffcc8d0fb
@ -28,5 +28,5 @@ android {
|
||||
dependencies {
|
||||
implementation project(':usbSerialForAndroid')
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'com.google.android.material:material:1.2.1'
|
||||
implementation 'com.google.android.material:material:1.3.0'
|
||||
}
|
||||
|
@ -780,6 +780,30 @@ public class DeviceTest {
|
||||
assertEquals(availableDrivers.get(0).getClass(), usb.serialDriver.getClass());
|
||||
}
|
||||
|
||||
// return [write packet size, write buffer size(s)]
|
||||
private int[] getWriteSizes() {
|
||||
if (usb.serialDriver instanceof Cp21xxSerialDriver) {
|
||||
if (usb.serialDriver.getPorts().size() == 1) return new int[]{64, 576};
|
||||
else if (usb.serialPort.getPortNumber() == 0) return new int[]{64, 320};
|
||||
else return new int[]{32, 128, 160}; // write buffer size detection is unreliable
|
||||
} else if (usb.serialDriver instanceof Ch34xSerialDriver) {
|
||||
return new int[]{32, 64};
|
||||
} else if (usb.serialDriver instanceof ProlificSerialDriver) {
|
||||
return new int[]{64, 256};
|
||||
} else if (usb.serialDriver instanceof FtdiSerialDriver) {
|
||||
switch (usb.serialDriver.getPorts().size()) {
|
||||
case 1: return new int[]{64, 128};
|
||||
case 2: return new int[]{512, 4096};
|
||||
case 4: return new int[]{512, 2048};
|
||||
default: return null;
|
||||
}
|
||||
} else if (usb.serialDriver instanceof CdcAcmSerialDriver) {
|
||||
return new int[]{64, 128};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeTimeout() throws Exception {
|
||||
usb.open();
|
||||
@ -806,29 +830,10 @@ public class DeviceTest {
|
||||
|
||||
int writeBufferSize = writePacketSize * writePackets;
|
||||
Log.d(TAG, "write packet size = " + writePacketSize + ", write buffer size = " + writeBufferSize);
|
||||
if(usb.serialDriver instanceof Cp21xxSerialDriver) {
|
||||
switch(usb.serialDriver.getPorts().size()*0x10 + usb.serialPort.getPortNumber()) {
|
||||
case 0x10: assertEquals("write packet size", 64, writePacketSize); assertEquals("write buffer size", 576, writeBufferSize); break;
|
||||
case 0x20: assertEquals("write packet size", 64, writePacketSize); assertEquals("write buffer size", 320, writeBufferSize); break;
|
||||
case 0x21: assertEquals("write packet size", 32, writePacketSize); assertTrue("write buffer size", writeBufferSize == 128 || writeBufferSize == 160); break;
|
||||
default: fail("unknown port number");
|
||||
}
|
||||
} else if(usb.serialDriver instanceof Ch34xSerialDriver) {
|
||||
assertEquals("write packet size", 32, writePacketSize); assertEquals("write buffer size", 64, writeBufferSize);
|
||||
} else if(usb.serialDriver instanceof ProlificSerialDriver) {
|
||||
assertEquals("write packet size", 64, writePacketSize); assertEquals("write buffer size", 256, writeBufferSize);
|
||||
} else if(usb.serialDriver instanceof FtdiSerialDriver) {
|
||||
switch(usb.serialDriver.getPorts().size()) {
|
||||
case 1: assertEquals("write packet size", 64, writePacketSize); assertEquals("write buffer size", 128, writeBufferSize); break;
|
||||
case 2: assertEquals("write packet size", 512, writePacketSize); assertEquals("write buffer size", 4096, writeBufferSize); break;
|
||||
case 4: assertEquals("write packet size", 512, writePacketSize); assertEquals( "write buffer size", 2048, writeBufferSize); break;
|
||||
default: fail("unknown port number");
|
||||
}
|
||||
} else if(usb.serialDriver instanceof CdcAcmSerialDriver) {
|
||||
assertEquals(64, writePacketSize); assertEquals(128, writeBufferSize); // values for ATMega32U4
|
||||
} else {
|
||||
fail("unknown driver " + usb.serialDriver.getClass().getSimpleName());
|
||||
}
|
||||
int[] writeSizes = getWriteSizes();
|
||||
assertNotNull(writeSizes);
|
||||
assertEquals("write packet size", writeSizes[0], writePacketSize);
|
||||
assertTrue("write buffer size", Arrays.binarySearch(writeSizes, writeBufferSize) > 0);
|
||||
purgeWriteBuffer(purgeTimeout);
|
||||
if(usb.serialDriver instanceof CdcAcmSerialDriver)
|
||||
return; // serial processing to slow for tests below, but they anyway only check shared code in CommonUsbSerialPort
|
||||
@ -839,26 +844,6 @@ public class DeviceTest {
|
||||
telnet.setParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE);
|
||||
TestBuffer tbuf;
|
||||
|
||||
// compare write time
|
||||
// full write @ 1-2 msec
|
||||
// packet write @ 5-10 msec
|
||||
if(false) {
|
||||
tbuf = new TestBuffer(writeBufferSize);
|
||||
((CommonUsbSerialPort) usb.serialPort).setWriteBufferSize(tbuf.buf.length);
|
||||
Log.d(TAG, "full write begin");
|
||||
long begin = System.currentTimeMillis();
|
||||
usb.serialPort.write(tbuf.buf, 0);
|
||||
Log.d(TAG, "full write end, duration=" + (System.currentTimeMillis() - begin));
|
||||
purgeWriteBuffer(purgeTimeout);
|
||||
((CommonUsbSerialPort) usb.serialPort).setWriteBufferSize(writePacketSize);
|
||||
Log.d(TAG, "packet write begin");
|
||||
begin = System.currentTimeMillis();
|
||||
usb.serialPort.write(tbuf.buf, 0);
|
||||
Log.d(TAG, "packet write end, duration=" + (System.currentTimeMillis() - begin));
|
||||
purgeWriteBuffer(purgeTimeout);
|
||||
Assume.assumeTrue(false);
|
||||
}
|
||||
|
||||
// total write timeout
|
||||
tbuf = new TestBuffer(writeBufferSize + writePacketSize);
|
||||
int timeout = writePacketSize / 32 * 50; // time for 1.5 packets. write 48 byte in 50 msec at 9600 baud
|
||||
@ -873,17 +858,18 @@ public class DeviceTest {
|
||||
purgeWriteBuffer(purgeTimeout);
|
||||
|
||||
// infinite wait
|
||||
//((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(writePacketSize);
|
||||
((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(writePacketSize);
|
||||
usb.serialPort.write(tbuf.buf, 0);
|
||||
purgeWriteBuffer(purgeTimeout);
|
||||
|
||||
// SerialTimeoutException.bytesTransferred
|
||||
// timeout in bulkTransfer + SerialTimeoutException.bytesTransferred
|
||||
int readWait = writePacketSize > 64 ? 250 : 50;
|
||||
((CommonUsbSerialPort)usb.serialPort).setWriteBufferSize(tbuf.buf.length);
|
||||
try {
|
||||
usb.serialPort.write(tbuf.buf, timeout);
|
||||
fail("write error expected");
|
||||
} catch(SerialTimeoutException ex) {
|
||||
assertTrue(ex.getMessage(), ex.getMessage().endsWith("rc=-1")); // timeout in bulkTransfer
|
||||
for(byte[] data = telnet.read(-1, readWait); data.length != 0;
|
||||
data = telnet.read(-1, readWait)) {
|
||||
tbuf.testRead(data);
|
||||
@ -898,6 +884,7 @@ public class DeviceTest {
|
||||
usb.serialPort.write(tbuf.buf, timeout);
|
||||
fail("write error expected");
|
||||
} catch(SerialTimeoutException ex) {
|
||||
assertTrue(ex.getMessage(), ex.getMessage().endsWith("rc=-1")); // timeout in bulkTransfer
|
||||
for(byte[] data = telnet.read(-1, readWait); data.length != 0;
|
||||
data = telnet.read(-1, readWait)) {
|
||||
tbuf.testRead(data);
|
||||
@ -906,6 +893,79 @@ public class DeviceTest {
|
||||
assertEquals(writeBufferSize + writePacketSize, tbuf.len);
|
||||
}
|
||||
purgeWriteBuffer(purgeTimeout);
|
||||
|
||||
// timeout in library
|
||||
timeout = 1;
|
||||
try {
|
||||
usb.serialPort.write(tbuf.buf, timeout);
|
||||
fail("write error expected");
|
||||
} catch (SerialTimeoutException ex) {
|
||||
assertTrue(ex.getMessage(), ex.getMessage().endsWith("rc=-2")); // timeout in library
|
||||
}
|
||||
purgeWriteBuffer(purgeTimeout);
|
||||
}
|
||||
|
||||
@Test
|
||||
// compare write duration.
|
||||
//
|
||||
// multiple packet sized writes typically take 2-3X time of single full buffer write.
|
||||
// here some typical durations:
|
||||
// full packet [msec]
|
||||
// Prolific 4 8
|
||||
// Cp2102 3 10
|
||||
// CP2105 1.x 2-3
|
||||
// FT232 1.5-2 2-3
|
||||
// Ch34x 1.x 2-3
|
||||
// CDC 1.x 2-3
|
||||
public void writeDuration() throws Exception {
|
||||
usb.open();
|
||||
usb.setParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE);
|
||||
telnet.setParameters(9600, 8, 1, UsbSerialPort.PARITY_NONE);
|
||||
|
||||
boolean purge = true;
|
||||
try {
|
||||
usb.serialPort.purgeHwBuffers(true, false);
|
||||
} catch(Exception ignored) {
|
||||
purge = false;
|
||||
}
|
||||
if(usb.serialDriver instanceof Cp21xxSerialDriver && usb.serialDriver.getPorts().size() == 1)
|
||||
purge = false; // purge is blocking
|
||||
|
||||
int[] writeSizes = getWriteSizes();
|
||||
int writePacketSize = writeSizes[0];
|
||||
int writeBufferSize = writeSizes[1];
|
||||
int purgeTimeout = 250;
|
||||
TestBuffer tbuf;
|
||||
long begin;
|
||||
int duration1, duration2, retries, i, timeout;
|
||||
retries = purge ? 10 : 1;
|
||||
tbuf = new TestBuffer(writeBufferSize);
|
||||
|
||||
((CommonUsbSerialPort) usb.serialPort).setWriteBufferSize(tbuf.buf.length);
|
||||
Log.d(TAG, "writeDuration: full write begin");
|
||||
begin = System.currentTimeMillis();
|
||||
for(i=0; i<retries; i++) {
|
||||
usb.serialPort.write(tbuf.buf, 0);
|
||||
if(purge)
|
||||
usb.serialPort.purgeHwBuffers(true, false);
|
||||
}
|
||||
duration1 = (int)(System.currentTimeMillis() - begin);
|
||||
if(!purge)
|
||||
purgeWriteBuffer(purgeTimeout);
|
||||
Log.d(TAG, "writeDuration: full write end, duration " + duration1/(float)(retries) + " msec");
|
||||
((CommonUsbSerialPort) usb.serialPort).setWriteBufferSize(writePacketSize);
|
||||
Log.d(TAG, "writeDuration: packet write begin");
|
||||
begin = System.currentTimeMillis();
|
||||
for(i=0; i<retries; i++) {
|
||||
usb.serialPort.write(tbuf.buf, 0);
|
||||
if(purge)
|
||||
usb.serialPort.purgeHwBuffers(true, false);
|
||||
}
|
||||
duration2 = (int)(System.currentTimeMillis() - begin);
|
||||
purgeWriteBuffer(purgeTimeout);
|
||||
Log.d(TAG, "writeDuration: packet write end, duration " + duration2/(float)(retries) + " msec");
|
||||
assertTrue("full duration " + duration1 + ", packet duration " + duration2, duration1 < duration2);
|
||||
assertTrue("full duration " + duration1 + ", packet duration " + duration2, duration2 < 5*duration1);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -5,10 +5,10 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbDeviceConnection;
|
||||
import android.hardware.usb.UsbManager;
|
||||
import android.os.Process;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import com.hoho.android.usbserial.driver.CdcAcmSerialDriver;
|
||||
@ -24,12 +24,7 @@ import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
|
||||
|
||||
public class UsbWrapper implements SerialInputOutputManager.Listener {
|
||||
|
||||
@ -64,6 +59,9 @@ public class UsbWrapper implements SerialInputOutputManager.Listener {
|
||||
public void setUp() throws Exception {
|
||||
UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
|
||||
if (!usbManager.hasPermission(serialDriver.getDevice())) {
|
||||
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
|
||||
RingtoneManager.getRingtone(context, notification).play();
|
||||
|
||||
Log.d(TAG,"USB permission ...");
|
||||
final Boolean[] granted = {null};
|
||||
BroadcastReceiver usbReceiver = new BroadcastReceiver() {
|
||||
|
@ -205,15 +205,15 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
||||
@Override
|
||||
public void write(final byte[] src, final int timeout) throws IOException {
|
||||
int offset = 0;
|
||||
int requestTimeout = timeout;
|
||||
final long endTime = (timeout == 0) ? 0 : (System.currentTimeMillis() + timeout);
|
||||
|
||||
if(mConnection == null) {
|
||||
throw new IOException("Connection closed");
|
||||
}
|
||||
while (offset < src.length) {
|
||||
final int requestTimeout;
|
||||
final int requestLength;
|
||||
final int actualLength;
|
||||
final int requestDuration;
|
||||
|
||||
synchronized (mWriteBufferLock) {
|
||||
final byte[] writeBuffer;
|
||||
@ -226,24 +226,21 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
||||
System.arraycopy(src, offset, mWriteBuffer, 0, requestLength);
|
||||
writeBuffer = mWriteBuffer;
|
||||
}
|
||||
if (timeout == 0 || offset == 0) {
|
||||
requestTimeout = timeout;
|
||||
} else {
|
||||
requestTimeout = (int)(endTime - System.currentTimeMillis());
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
Log.d(TAG, "Wrote " + actualLength + "/" + requestLength + " offset " + offset + "/" + src.length + " timeout " + requestTimeout);
|
||||
if (requestTimeout > 0) {
|
||||
requestTimeout -= requestDuration;
|
||||
if (requestTimeout == 0)
|
||||
requestTimeout = -1;
|
||||
}
|
||||
if (actualLength <= 0) {
|
||||
if(requestTimeout < 0) {
|
||||
SerialTimeoutException ex = new SerialTimeoutException("Error writing " + requestLength + " bytes at offset " + offset + " of total " + src.length);
|
||||
if (timeout != 0 && System.currentTimeMillis() >= endTime) {
|
||||
SerialTimeoutException ex = new SerialTimeoutException("Error writing " + requestLength + " bytes at offset " + offset + " of total " + src.length + ", rc=" + actualLength);
|
||||
ex.bytesTransferred = offset;
|
||||
throw ex;
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user