mirror of
				https://github.com/mik3y/usb-serial-for-android
				synced 2025-10-31 02:17:23 +00:00 
			
		
		
		
	test concurrent access on multi-port devices
This commit is contained in:
		
							parent
							
								
									1f35587739
								
							
						
					
					
						commit
						b853ac773c
					
				| @ -14,6 +14,7 @@ import android.util.Log; | |||||||
| import com.hoho.android.usbserial.driver.UsbSerialDriver; | import com.hoho.android.usbserial.driver.UsbSerialDriver; | ||||||
| import com.hoho.android.usbserial.driver.UsbSerialPort; | import com.hoho.android.usbserial.driver.UsbSerialPort; | ||||||
| import com.hoho.android.usbserial.driver.UsbSerialProber; | import com.hoho.android.usbserial.driver.UsbSerialProber; | ||||||
|  | import com.hoho.android.usbserial.util.TestBuffer; | ||||||
| import com.hoho.android.usbserial.util.UsbWrapper; | import com.hoho.android.usbserial.util.UsbWrapper; | ||||||
| 
 | 
 | ||||||
| import org.junit.Before; | import org.junit.Before; | ||||||
| @ -24,12 +25,14 @@ import org.junit.rules.TestWatcher; | |||||||
| import org.junit.runner.Description; | import org.junit.runner.Description; | ||||||
| import org.junit.runner.RunWith; | import org.junit.runner.RunWith; | ||||||
| 
 | 
 | ||||||
|  | import java.io.IOException; | ||||||
| import java.util.EnumSet; | import java.util.EnumSet; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| 
 | 
 | ||||||
| import static org.hamcrest.CoreMatchers.equalTo; | import static org.hamcrest.CoreMatchers.equalTo; | ||||||
| import static org.junit.Assert.assertEquals; | import static org.junit.Assert.assertEquals; | ||||||
| import static org.junit.Assert.assertNotEquals; | import static org.junit.Assert.assertNotEquals; | ||||||
|  | import static org.junit.Assert.assertNull; | ||||||
| import static org.junit.Assert.assertThat; | import static org.junit.Assert.assertThat; | ||||||
| import static org.junit.Assert.fail; | import static org.junit.Assert.fail; | ||||||
| import static org.junit.Assume.assumeTrue; | import static org.junit.Assume.assumeTrue; | ||||||
| @ -160,4 +163,53 @@ public class CrossoverTest { | |||||||
|         usb2.close(); |         usb2.close(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Test | ||||||
|  |     public void concurrent() throws Exception { | ||||||
|  |         // 115200 baud ~= 11kB/sec => ~1.5 second test duration with 16kB tbuf | ||||||
|  |         // concurrent (+ blocking) write calls as tbuf larger than any buffer size returned by UsbWrapper.getWriteSizes() | ||||||
|  |         // concurrent read calls in IoManager threads | ||||||
|  |         TestBuffer tbuf1 = new TestBuffer(16*1024); | ||||||
|  |         TestBuffer tbuf2 = new TestBuffer(16*1024); | ||||||
|  | 
 | ||||||
|  |         class WriteRunnable implements Runnable { | ||||||
|  |             public WriteRunnable(int port) { this.port = port; } | ||||||
|  |             private final int port; | ||||||
|  |             Exception exc; | ||||||
|  |             @Override | ||||||
|  |             public void run() { | ||||||
|  |                 byte[] buf = new byte[1024]; | ||||||
|  |                 try { | ||||||
|  |                     for(int i=0; i<tbuf1.buf.length / 1024; i++) { | ||||||
|  |                         System.arraycopy(tbuf1.buf, i*1024, buf, 0, 1024); | ||||||
|  |                         if (port == 1) | ||||||
|  |                             usb1.write(buf); | ||||||
|  |                         else | ||||||
|  |                             usb2.write(buf); | ||||||
|  |                     } | ||||||
|  |                 } catch (IOException exc) { | ||||||
|  |                     this.exc = exc; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         usb1.open(); | ||||||
|  |         usb2.open(); | ||||||
|  |         usb1.setParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); | ||||||
|  |         usb2.setParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE); | ||||||
|  |         WriteRunnable wr1 = new WriteRunnable(1), wr2 = new WriteRunnable(2); | ||||||
|  |         Thread wt1 = new Thread(wr1), wt2 = new Thread(wr2); | ||||||
|  |         boolean done1 = false, done2 = false; | ||||||
|  |         wt1.start(); | ||||||
|  |         Thread.sleep(50); | ||||||
|  |         wt2.start(); | ||||||
|  |         while(!done1 && !done2) { | ||||||
|  |             if(!done1) | ||||||
|  |                 done1 = tbuf1.testRead(usb1.read(-1)); | ||||||
|  |             if(!done2) | ||||||
|  |                 done2 = tbuf2.testRead(usb2.read(-1)); | ||||||
|  |         } | ||||||
|  |         wt1.join(); wt2.join(); | ||||||
|  |         assertNull(wr1.exc); | ||||||
|  |         assertNull(wr2.exc); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -34,6 +34,7 @@ import com.hoho.android.usbserial.driver.UsbSerialPort; | |||||||
| import com.hoho.android.usbserial.driver.UsbSerialProber; | import com.hoho.android.usbserial.driver.UsbSerialProber; | ||||||
| import com.hoho.android.usbserial.util.SerialInputOutputManager; | import com.hoho.android.usbserial.util.SerialInputOutputManager; | ||||||
| import com.hoho.android.usbserial.util.TelnetWrapper; | import com.hoho.android.usbserial.util.TelnetWrapper; | ||||||
|  | import com.hoho.android.usbserial.util.TestBuffer; | ||||||
| import com.hoho.android.usbserial.util.UsbWrapper; | import com.hoho.android.usbserial.util.UsbWrapper; | ||||||
| 
 | 
 | ||||||
| import org.junit.After; | import org.junit.After; | ||||||
| @ -145,34 +146,6 @@ public class DeviceTest { | |||||||
|         telnet.tearDownFixture(); |         telnet.tearDownFixture(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static class TestBuffer { |  | ||||||
|         private final byte[] buf; |  | ||||||
|         private int len; |  | ||||||
| 
 |  | ||||||
|         private TestBuffer(int length) { |  | ||||||
|             len = 0; |  | ||||||
|             buf = new byte[length]; |  | ||||||
|             int i=0; |  | ||||||
|             int j=0; |  | ||||||
|             for(j=0; j<length/16; j++) |  | ||||||
|                 for(int k=0; k<16; k++) |  | ||||||
|                     buf[i++]=(byte)j; |  | ||||||
|             while(i<length) |  | ||||||
|                 buf[i++]=(byte)j; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private boolean testRead(byte[] data) { |  | ||||||
|             assertNotEquals(0, data.length); |  | ||||||
|             assertTrue("got " + (len+data.length) +" bytes", (len+data.length) <= buf.length); |  | ||||||
|             for(int j=0; j<data.length; j++) |  | ||||||
|                 assertEquals("at pos "+(len+j), (byte)((len+j)/16), data[j]); |  | ||||||
|             len += data.length; |  | ||||||
|             //Log.d(TAG, "read " + len); |  | ||||||
|             return len == buf.length; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     // clone of org.apache.commons.lang3.StringUtils.indexOfDifference + optional startpos |     // clone of org.apache.commons.lang3.StringUtils.indexOfDifference + optional startpos | ||||||
|     private static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) { |     private static int indexOfDifference(final CharSequence cs1, final CharSequence cs2) { | ||||||
|         return indexOfDifference(cs1, cs2, 0, 0); |         return indexOfDifference(cs1, cs2, 0, 0); | ||||||
| @ -816,30 +789,6 @@ public class DeviceTest { | |||||||
|         assertEquals(availableDrivers.get(0).getClass(), usb.serialDriver.getClass()); |         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 |     @Test | ||||||
|     public void writeTimeout() throws Exception { |     public void writeTimeout() throws Exception { | ||||||
|         usb.open(); |         usb.open(); | ||||||
| @ -866,7 +815,7 @@ public class DeviceTest { | |||||||
| 
 | 
 | ||||||
|         int writeBufferSize = writePacketSize * writePackets; |         int writeBufferSize = writePacketSize * writePackets; | ||||||
|         Log.d(TAG, "write packet size = " + writePacketSize + ", write buffer size = " + writeBufferSize); |         Log.d(TAG, "write packet size = " + writePacketSize + ", write buffer size = " + writeBufferSize); | ||||||
|         int[] writeSizes = getWriteSizes(); |         int[] writeSizes = usb.getWriteSizes(); | ||||||
|         assertNotNull(writeSizes); |         assertNotNull(writeSizes); | ||||||
|         assertEquals("write packet size", writeSizes[0], writePacketSize); |         assertEquals("write packet size", writeSizes[0], writePacketSize); | ||||||
|         assertTrue("write buffer size", Arrays.binarySearch(writeSizes, writeBufferSize) > 0); |         assertTrue("write buffer size", Arrays.binarySearch(writeSizes, writeBufferSize) > 0); | ||||||
| @ -967,7 +916,7 @@ public class DeviceTest { | |||||||
|         if(usb.serialDriver instanceof Cp21xxSerialDriver && usb.serialDriver.getPorts().size() == 1) |         if(usb.serialDriver instanceof Cp21xxSerialDriver && usb.serialDriver.getPorts().size() == 1) | ||||||
|             purge = false; // purge is blocking |             purge = false; // purge is blocking | ||||||
| 
 | 
 | ||||||
|         int[] writeSizes = getWriteSizes(); |         int[] writeSizes = usb.getWriteSizes(); | ||||||
|         int writePacketSize = writeSizes[0]; |         int writePacketSize = writeSizes[0]; | ||||||
|         int writeBufferSize = writeSizes[1]; |         int writeBufferSize = writeSizes[1]; | ||||||
|         int purgeTimeout = 250; |         int purgeTimeout = 250; | ||||||
|  | |||||||
| @ -0,0 +1,32 @@ | |||||||
|  | package com.hoho.android.usbserial.util; | ||||||
|  | 
 | ||||||
|  | import static org.junit.Assert.assertEquals; | ||||||
|  | import static org.junit.Assert.assertNotEquals; | ||||||
|  | import static org.junit.Assert.assertTrue; | ||||||
|  | 
 | ||||||
|  | public class TestBuffer { | ||||||
|  |     public final byte[] buf; | ||||||
|  |     public int len; | ||||||
|  | 
 | ||||||
|  |     public TestBuffer(int length) { | ||||||
|  |         len = 0; | ||||||
|  |         buf = new byte[length]; | ||||||
|  |         int i = 0; | ||||||
|  |         int j = 0; | ||||||
|  |         for (j = 0; j < length / 16; j++) | ||||||
|  |             for (int k = 0; k < 16; k++) | ||||||
|  |                 buf[i++] = (byte) j; | ||||||
|  |         while (i < length) | ||||||
|  |             buf[i++] = (byte) j; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public boolean testRead(byte[] data) { | ||||||
|  |         assertNotEquals(0, data.length); | ||||||
|  |         assertTrue("got " + (len + data.length) + " bytes", (len + data.length) <= buf.length); | ||||||
|  |         for (int j = 0; j < data.length; j++) | ||||||
|  |             assertEquals("at pos " + (len + j), (byte) ((len + j) / 16), data[j]); | ||||||
|  |         len += data.length; | ||||||
|  |         //Log.d(TAG, "read " + len); | ||||||
|  |         return len == buf.length; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -12,7 +12,11 @@ import android.net.Uri; | |||||||
| import android.util.Log; | import android.util.Log; | ||||||
| 
 | 
 | ||||||
| import com.hoho.android.usbserial.driver.CdcAcmSerialDriver; | import com.hoho.android.usbserial.driver.CdcAcmSerialDriver; | ||||||
|  | import com.hoho.android.usbserial.driver.Ch34xSerialDriver; | ||||||
| import com.hoho.android.usbserial.driver.CommonUsbSerialPort; | import com.hoho.android.usbserial.driver.CommonUsbSerialPort; | ||||||
|  | import com.hoho.android.usbserial.driver.Cp21xxSerialDriver; | ||||||
|  | import com.hoho.android.usbserial.driver.FtdiSerialDriver; | ||||||
|  | import com.hoho.android.usbserial.driver.ProlificSerialDriver; | ||||||
| import com.hoho.android.usbserial.driver.UsbSerialDriver; | import com.hoho.android.usbserial.driver.UsbSerialDriver; | ||||||
| import com.hoho.android.usbserial.driver.UsbSerialPort; | import com.hoho.android.usbserial.driver.UsbSerialPort; | ||||||
| 
 | 
 | ||||||
| @ -246,15 +250,40 @@ public class UsbWrapper implements SerialInputOutputManager.Listener { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // return [write packet size, write buffer size(s)] | ||||||
|  |     public int[] getWriteSizes() { | ||||||
|  |         if (serialDriver instanceof Cp21xxSerialDriver) { | ||||||
|  |             if (serialDriver.getPorts().size() == 1) return new int[]{64, 576}; | ||||||
|  |             else if (serialPort.getPortNumber() == 0) return new int[]{64, 320}; | ||||||
|  |             else return new int[]{32, 128, 160}; // write buffer size detection is unreliable | ||||||
|  |         } else if (serialDriver instanceof Ch34xSerialDriver) { | ||||||
|  |             return new int[]{32, 64}; | ||||||
|  |         } else if (serialDriver instanceof ProlificSerialDriver) { | ||||||
|  |             return new int[]{64, 256}; | ||||||
|  |         } else if (serialDriver instanceof FtdiSerialDriver) { | ||||||
|  |             switch (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 (serialDriver instanceof CdcAcmSerialDriver) { | ||||||
|  |             return new int[]{64, 128}; | ||||||
|  |         } else { | ||||||
|  |             return null; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void onNewData(byte[] data) { |     public void onNewData(byte[] data) { | ||||||
|         long now = System.currentTimeMillis(); |         long now = System.currentTimeMillis(); | ||||||
|         if(readTime == 0) |         if(readTime == 0) | ||||||
|             readTime = now; |             readTime = now; | ||||||
|         if(data.length > 64) { |         if(data.length > 64) { | ||||||
|             Log.d(TAG, "usb read: time+=" + String.format("%-3d",now- readTime) + " len=" + String.format("%-4d",data.length) + " data=" + new String(data, 0, 32) + "..." + new String(data, data.length-32, 32)); |             Log.d(TAG, "usb " + devicePort + " read: time+=" + String.format("%-3d",now- readTime) + " len=" + String.format("%-4d",data.length) + " data=" + new String(data, 0, 32) + "..." + new String(data, data.length-32, 32)); | ||||||
|         } else { |         } else { | ||||||
|             Log.d(TAG, "usb read: time+=" + String.format("%-3d",now- readTime) + " len=" + String.format("%-4d",data.length) + " data=" + new String(data)); |             Log.d(TAG, "usb " + devicePort + " read: time+=" + String.format("%-3d",now- readTime) + " len=" + String.format("%-4d",data.length) + " data=" + new String(data)); | ||||||
|         } |         } | ||||||
|         readTime = now; |         readTime = now; | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user