mirror of
https://github.com/mik3y/usb-serial-for-android
synced 2025-07-23 18:05:26 +00:00
iomanager with configurable buffer size
This commit is contained in:
parent
4f2d6c73a4
commit
f443d1f012
@ -45,6 +45,7 @@ import org.junit.runner.Description;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.BufferOverflowException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -56,6 +57,7 @@ import static org.junit.Assert.assertEquals;
|
|||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotEquals;
|
import static org.junit.Assert.assertNotEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
@ -1014,6 +1016,82 @@ public class DeviceTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void IoManager() throws Exception {
|
||||||
|
usb.ioManager = new SerialInputOutputManager(null);
|
||||||
|
assertNull(usb.ioManager.getListener());
|
||||||
|
usb.ioManager.setListener(usb);
|
||||||
|
assertEquals(usb, usb.ioManager.getListener());
|
||||||
|
usb.ioManager = new SerialInputOutputManager(usb.serialPort, usb);
|
||||||
|
assertEquals(usb, usb.ioManager.getListener());
|
||||||
|
|
||||||
|
assertEquals(0, usb.ioManager.getReadTimeout());
|
||||||
|
usb.ioManager.setReadTimeout(10);
|
||||||
|
assertEquals(10, usb.ioManager.getReadTimeout());
|
||||||
|
assertEquals(0, usb.ioManager.getWriteTimeout());
|
||||||
|
usb.ioManager.setWriteTimeout(11);
|
||||||
|
assertEquals(11, usb.ioManager.getWriteTimeout());
|
||||||
|
|
||||||
|
assertEquals(4096, usb.ioManager.getReadBufferSize());
|
||||||
|
usb.ioManager.setReadBufferSize(12);
|
||||||
|
assertEquals(12, usb.ioManager.getReadBufferSize());
|
||||||
|
assertEquals(4096, usb.ioManager.getWriteBufferSize());
|
||||||
|
usb.ioManager.setWriteBufferSize(13);
|
||||||
|
assertEquals(13, usb.ioManager.getWriteBufferSize());
|
||||||
|
|
||||||
|
usb.open(); // creates new IoManager
|
||||||
|
usb.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
|
||||||
|
telnet.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
|
||||||
|
usb.waitForIoManagerStarted();
|
||||||
|
try {
|
||||||
|
usb.ioManager.setReadTimeout(20);
|
||||||
|
fail("setReadTimeout IllegalStateException expected");
|
||||||
|
} catch (IllegalStateException ignored) {}
|
||||||
|
assertEquals(0, usb.ioManager.getReadTimeout());
|
||||||
|
usb.ioManager.setWriteTimeout(21);
|
||||||
|
assertEquals(21, usb.ioManager.getWriteTimeout());
|
||||||
|
usb.ioManager.setReadBufferSize(22);
|
||||||
|
assertEquals(22, usb.ioManager.getReadBufferSize());
|
||||||
|
usb.ioManager.setWriteBufferSize(23);
|
||||||
|
assertEquals(23, usb.ioManager.getWriteBufferSize());
|
||||||
|
|
||||||
|
// readbuffer resize
|
||||||
|
telnet.write(new byte[1]);
|
||||||
|
usb.ioManager.setReadBufferSize(64);
|
||||||
|
Log.d(TAG, "setReadBufferSize(64)");
|
||||||
|
telnet.write(new byte[1]); // still uses old buffer as infinite waiting step() holds reference to buffer
|
||||||
|
telnet.write(new byte[1]); // now uses 8 byte buffer
|
||||||
|
usb.read(3);
|
||||||
|
|
||||||
|
// writebuffer resize
|
||||||
|
try {
|
||||||
|
usb.ioManager.writeAsync(new byte[8192]);
|
||||||
|
fail("expected BufferOverflowException");
|
||||||
|
} catch (BufferOverflowException ignored) {}
|
||||||
|
|
||||||
|
usb.ioManager.setWriteBufferSize(16);
|
||||||
|
usb.ioManager.writeAsync("1234567890AB".getBytes());
|
||||||
|
try {
|
||||||
|
usb.ioManager.setWriteBufferSize(8);
|
||||||
|
fail("expected BufferOverflowException");
|
||||||
|
} catch (BufferOverflowException ignored) {}
|
||||||
|
usb.ioManager.setWriteBufferSize(24); // pending date copied to new buffer
|
||||||
|
telnet.write("a".getBytes());
|
||||||
|
assertThat(usb.read(1), equalTo("a".getBytes()));
|
||||||
|
assertThat(telnet.read(12), equalTo("1234567890AB".getBytes()));
|
||||||
|
|
||||||
|
// small readbuffer
|
||||||
|
usb.ioManager.setReadBufferSize(8);
|
||||||
|
Log.d(TAG, "setReadBufferSize(8)");
|
||||||
|
telnet.write("b".getBytes());
|
||||||
|
assertThat(usb.read(1), equalTo("b".getBytes()));
|
||||||
|
// now new buffer is used
|
||||||
|
telnet.write("c".getBytes());
|
||||||
|
assertThat(usb.read(1), equalTo("c".getBytes()));
|
||||||
|
telnet.write("d".getBytes());
|
||||||
|
assertThat(usb.read(1), equalTo("d".getBytes()));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void writeAsync() throws Exception {
|
public void writeAsync() throws Exception {
|
||||||
if (usb.serialDriver instanceof FtdiSerialDriver)
|
if (usb.serialDriver instanceof FtdiSerialDriver)
|
||||||
@ -1021,19 +1099,6 @@ public class DeviceTest {
|
|||||||
|
|
||||||
byte[] data, buf = new byte[]{1};
|
byte[] data, buf = new byte[]{1};
|
||||||
|
|
||||||
usb.ioManager = new SerialInputOutputManager(null);
|
|
||||||
assertEquals(null, usb.ioManager.getListener());
|
|
||||||
usb.ioManager.setListener(usb);
|
|
||||||
assertEquals(usb, usb.ioManager.getListener());
|
|
||||||
usb.ioManager = new SerialInputOutputManager(usb.serialPort, usb);
|
|
||||||
assertEquals(usb, usb.ioManager.getListener());
|
|
||||||
assertEquals(0, usb.ioManager.getReadTimeout());
|
|
||||||
usb.ioManager.setReadTimeout(100);
|
|
||||||
assertEquals(100, usb.ioManager.getReadTimeout());
|
|
||||||
assertEquals(0, usb.ioManager.getWriteTimeout());
|
|
||||||
usb.ioManager.setWriteTimeout(200);
|
|
||||||
assertEquals(200, usb.ioManager.getWriteTimeout());
|
|
||||||
|
|
||||||
// w/o timeout: write delayed until something is read
|
// w/o timeout: write delayed until something is read
|
||||||
usb.open();
|
usb.open();
|
||||||
usb.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
|
usb.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
|
||||||
@ -1047,10 +1112,6 @@ public class DeviceTest {
|
|||||||
assertEquals(1, data.length);
|
assertEquals(1, data.length);
|
||||||
data = telnet.read(2);
|
data = telnet.read(2);
|
||||||
assertEquals(2, data.length);
|
assertEquals(2, data.length);
|
||||||
try {
|
|
||||||
usb.ioManager.setReadTimeout(100);
|
|
||||||
fail("IllegalStateException expected");
|
|
||||||
} catch (IllegalStateException ignored) {}
|
|
||||||
usb.close();
|
usb.close();
|
||||||
|
|
||||||
// with timeout: write after timeout
|
// with timeout: write after timeout
|
||||||
|
@ -175,6 +175,18 @@ public class UsbWrapper implements SerialInputOutputManager.Listener {
|
|||||||
readError = null;
|
readError = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void waitForIoManagerStarted() throws IOException {
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
if (SerialInputOutputManager.State.STOPPED != ioManager.getState()) return;
|
||||||
|
try {
|
||||||
|
Thread.sleep(1);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IOException("IoManager not started");
|
||||||
|
}
|
||||||
|
|
||||||
// wait full time
|
// wait full time
|
||||||
public byte[] read() throws Exception {
|
public byte[] read() throws Exception {
|
||||||
return read(-1);
|
return read(-1);
|
||||||
|
@ -30,8 +30,11 @@ public class SerialInputOutputManager implements Runnable {
|
|||||||
private int mReadTimeout = 0;
|
private int mReadTimeout = 0;
|
||||||
private int mWriteTimeout = 0;
|
private int mWriteTimeout = 0;
|
||||||
|
|
||||||
private final ByteBuffer mReadBuffer = ByteBuffer.allocate(BUFSIZ);
|
private final Object mReadBufferLock = new Object();
|
||||||
private final ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ); // Synchronized by 'mWriteBuffer'
|
private final Object mWriteBufferLock = new Object();
|
||||||
|
|
||||||
|
private ByteBuffer mReadBuffer = ByteBuffer.allocate(BUFSIZ);
|
||||||
|
private ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);
|
||||||
|
|
||||||
public enum State {
|
public enum State {
|
||||||
STOPPED,
|
STOPPED,
|
||||||
@ -72,10 +75,13 @@ public class SerialInputOutputManager implements Runnable {
|
|||||||
return mListener;
|
return mListener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* read/write timeout
|
||||||
|
*/
|
||||||
public void setReadTimeout(int timeout) {
|
public void setReadTimeout(int timeout) {
|
||||||
// when set if already running, read already blocks and the new value will not become effective now
|
// when set if already running, read already blocks and the new value will not become effective now
|
||||||
if(mReadTimeout == 0 && timeout != 0 && mState != State.STOPPED)
|
if(mReadTimeout == 0 && timeout != 0 && mState != State.STOPPED)
|
||||||
throw new IllegalStateException("Set readTimeout before SerialInputOutputManager is started");
|
throw new IllegalStateException("readTimeout only configurable before SerialInputOutputManager is started");
|
||||||
mReadTimeout = timeout;
|
mReadTimeout = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,12 +97,42 @@ public class SerialInputOutputManager implements Runnable {
|
|||||||
return mWriteTimeout;
|
return mWriteTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* read/write buffer size
|
||||||
|
*/
|
||||||
|
public void setReadBufferSize(int bufferSize) {
|
||||||
|
if (getReadBufferSize() == bufferSize)
|
||||||
|
return;
|
||||||
|
synchronized (mReadBufferLock) {
|
||||||
|
mReadBuffer = ByteBuffer.allocate(bufferSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getReadBufferSize() {
|
||||||
|
return mReadBuffer.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWriteBufferSize(int bufferSize) {
|
||||||
|
if(getWriteBufferSize() == bufferSize)
|
||||||
|
return;
|
||||||
|
synchronized (mWriteBufferLock) {
|
||||||
|
ByteBuffer newWriteBuffer = ByteBuffer.allocate(bufferSize);
|
||||||
|
if(mWriteBuffer.position() > 0)
|
||||||
|
newWriteBuffer.put(mWriteBuffer.array(), 0, mWriteBuffer.position());
|
||||||
|
mWriteBuffer = newWriteBuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWriteBufferSize() {
|
||||||
|
return mWriteBuffer.capacity();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* when writeAsync is used, it is recommended to use readTimeout != 0,
|
* when writeAsync is used, it is recommended to use readTimeout != 0,
|
||||||
* else the write will be delayed until read data is available
|
* else the write will be delayed until read data is available
|
||||||
*/
|
*/
|
||||||
public void writeAsync(byte[] data) {
|
public void writeAsync(byte[] data) {
|
||||||
synchronized (mWriteBuffer) {
|
synchronized (mWriteBufferLock) {
|
||||||
mWriteBuffer.put(data);
|
mWriteBuffer.put(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,34 +186,37 @@ public class SerialInputOutputManager implements Runnable {
|
|||||||
|
|
||||||
private void step() throws IOException {
|
private void step() throws IOException {
|
||||||
// Handle incoming data.
|
// Handle incoming data.
|
||||||
int len = mSerialPort.read(mReadBuffer.array(), mReadTimeout);
|
byte[] buffer = null;
|
||||||
|
synchronized (mReadBufferLock) {
|
||||||
|
buffer = mReadBuffer.array();
|
||||||
|
}
|
||||||
|
int len = mSerialPort.read(buffer, mReadTimeout);
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
if (DEBUG) Log.d(TAG, "Read data len=" + len);
|
if (DEBUG) Log.d(TAG, "Read data len=" + len);
|
||||||
final Listener listener = getListener();
|
final Listener listener = getListener();
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
final byte[] data = new byte[len];
|
final byte[] data = new byte[len];
|
||||||
mReadBuffer.get(data, 0, len);
|
System.arraycopy(buffer, 0, data, 0, len);
|
||||||
listener.onNewData(data);
|
listener.onNewData(data);
|
||||||
}
|
}
|
||||||
mReadBuffer.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle outgoing data.
|
// Handle outgoing data.
|
||||||
byte[] outBuff = null;
|
buffer = null;
|
||||||
synchronized (mWriteBuffer) {
|
synchronized (mWriteBufferLock) {
|
||||||
len = mWriteBuffer.position();
|
len = mWriteBuffer.position();
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
outBuff = new byte[len];
|
buffer = new byte[len];
|
||||||
mWriteBuffer.rewind();
|
mWriteBuffer.rewind();
|
||||||
mWriteBuffer.get(outBuff, 0, len);
|
mWriteBuffer.get(buffer, 0, len);
|
||||||
mWriteBuffer.clear();
|
mWriteBuffer.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (outBuff != null) {
|
if (buffer != null) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "Writing data len=" + len);
|
Log.d(TAG, "Writing data len=" + len);
|
||||||
}
|
}
|
||||||
mSerialPort.write(outBuff, mWriteTimeout);
|
mSerialPort.write(buffer, mWriteTimeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user