mirror of
https://github.com/mik3y/usb-serial-for-android
synced 2025-06-07 16:06:10 +00:00
show code coverage
This commit is contained in:
parent
9755a4cb87
commit
54a3db115f
14
.idea/misc.xml
generated
14
.idea/misc.xml
generated
@ -5,7 +5,7 @@
|
|||||||
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
||||||
<option name="myNullables">
|
<option name="myNullables">
|
||||||
<value>
|
<value>
|
||||||
<list size="7">
|
<list size="12">
|
||||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
||||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
||||||
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
|
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
|
||||||
@ -13,18 +13,28 @@
|
|||||||
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
||||||
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
|
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
|
||||||
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
|
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
|
||||||
|
<item index="7" class="java.lang.String" itemvalue="android.annotation.Nullable" />
|
||||||
|
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
|
||||||
|
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
|
||||||
|
<item index="10" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
|
||||||
|
<item index="11" class="java.lang.String" itemvalue="com.android.annotations.Nullable" />
|
||||||
</list>
|
</list>
|
||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
<option name="myNotNulls">
|
<option name="myNotNulls">
|
||||||
<value>
|
<value>
|
||||||
<list size="6">
|
<list size="11">
|
||||||
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
||||||
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
||||||
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
||||||
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
||||||
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
|
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
|
||||||
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
|
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
|
||||||
|
<item index="6" class="java.lang.String" itemvalue="android.annotation.NonNull" />
|
||||||
|
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
|
||||||
|
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
|
||||||
|
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
|
||||||
|
<item index="10" class="java.lang.String" itemvalue="com.android.annotations.NonNull" />
|
||||||
</list>
|
</list>
|
||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
[](https://jitpack.io/#mik3y/usb-serial-for-android)
|
[](https://jitpack.io/#mik3y/usb-serial-for-android)
|
||||||
[](https://www.codacy.com/manual/kai-morich/usb-serial-for-android-mik3y?utm_source=github.com&utm_medium=referral&utm_content=mik3y/usb-serial-for-android&utm_campaign=Badge_Grade)
|
[](https://www.codacy.com/manual/kai-morich/usb-serial-for-android-mik3y?utm_source=github.com&utm_medium=referral&utm_content=mik3y/usb-serial-for-android&utm_campaign=Badge_Grade)
|
||||||
|
[](https://codecov.io/gh/mik3y/usb-serial-for-android)
|
||||||
|
|
||||||
# usb-serial-for-android
|
# usb-serial-for-android
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ buildscript {
|
|||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
classpath 'com.android.tools.build:gradle:3.5.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ android {
|
|||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
|
|
||||||
testInstrumentationRunner "android.test.InstrumentationTestRunner"
|
testInstrumentationRunner "android.test.InstrumentationTestRunner"
|
||||||
|
missingDimensionStrategy 'device', 'anyDevice'
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
@ -8,6 +8,11 @@ android {
|
|||||||
minSdkVersion 17
|
minSdkVersion 17
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
|
testInstrumentationRunnerArguments = [
|
||||||
|
'rfc2217_server_host': '192.168.0.171',
|
||||||
|
'rfc2217_server_nonstandard_baudrates': 'false', // false on Windows, Raspi
|
||||||
|
'rfc2217_server_parity_mark_space': 'true' // false on Raspi
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@ -26,7 +31,6 @@ dependencies {
|
|||||||
androidTestImplementation 'org.apache.commons:commons-lang3:3.8.1'
|
androidTestImplementation 'org.apache.commons:commons-lang3:3.8.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
// to build a .jar file use gradle task 'createFullJarRelease'
|
|
||||||
|
|
||||||
// to deploy into local maven repository use gradle task 'publishToMavenLocal' and enable:
|
|
||||||
//apply from: 'publishToMavenLocal.gradle'
|
//apply from: 'publishToMavenLocal.gradle'
|
||||||
|
|
||||||
|
//apply from: 'coverage.gradle'
|
||||||
|
45
usbSerialForAndroid/coverage.gradle
Normal file
45
usbSerialForAndroid/coverage.gradle
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
apply plugin: 'jacoco'
|
||||||
|
|
||||||
|
android {
|
||||||
|
flavorDimensions 'device'
|
||||||
|
productFlavors {
|
||||||
|
anyDevice {
|
||||||
|
// Used as fallback in usbSerialExample/build.gradle -> missingDimensionStrategy, but not for coverage report
|
||||||
|
dimension 'device'
|
||||||
|
}
|
||||||
|
arduino {
|
||||||
|
dimension 'device'
|
||||||
|
testInstrumentationRunnerArguments = ['test_device_driver': 'CdcAcm']
|
||||||
|
}
|
||||||
|
ch340 {
|
||||||
|
dimension 'device'
|
||||||
|
testInstrumentationRunnerArguments = ['test_device_driver': 'Ch34x']
|
||||||
|
}
|
||||||
|
cp2102 { // and cp2105 first port
|
||||||
|
dimension 'device'
|
||||||
|
testInstrumentationRunnerArguments = ['test_device_driver': 'Cp21xx']
|
||||||
|
}
|
||||||
|
cp2105 { // second port
|
||||||
|
dimension 'device'
|
||||||
|
testInstrumentationRunnerArguments = ['test_device_driver': 'Cp21xx', 'test_device_port': '1']
|
||||||
|
}
|
||||||
|
ft232 { // and ft2232 first port
|
||||||
|
dimension 'device'
|
||||||
|
testInstrumentationRunnerArguments = ['test_device_driver': 'Ftdi']
|
||||||
|
}
|
||||||
|
ft2232 { // second port
|
||||||
|
dimension 'device'
|
||||||
|
testInstrumentationRunnerArguments = ['test_device_driver': 'Ftdi', 'test_device_port': '1']
|
||||||
|
}
|
||||||
|
pl2302 {
|
||||||
|
dimension 'device'
|
||||||
|
testInstrumentationRunnerArguments = ['test_device_driver': 'Prolific']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
debug {
|
||||||
|
testCoverageEnabled true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,23 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* test setup
|
|
||||||
* - android device with ADB over Wi-Fi
|
|
||||||
* - to set up ADB over Wi-Fi with custom roms you typically can do it from: Android settings -> Developer options
|
|
||||||
* - for other devices you first have to manually connect over USB and enable Wi-Fi as shown here:
|
|
||||||
* https://developer.android.com/studio/command-line/adb.html
|
|
||||||
* - windows/linux machine running rfc2217_server.py
|
|
||||||
* python + pyserial + https://github.com/pyserial/pyserial/blob/master/examples/rfc2217_server.py
|
|
||||||
* for developing this test it was essential to see all data (see test/rfc2217_server.diff, run python script with '-v -v' option)
|
|
||||||
* - all suppported usb <-> serial converter
|
|
||||||
* as CDC test device use an arduino leonardo / pro mini programmed with arduino_leonardo_bridge.ino
|
|
||||||
*
|
|
||||||
* restrictions
|
* restrictions
|
||||||
* - as real hardware is used, timing might need tuning. see:
|
* - as real hardware is used, timing might need tuning. see:
|
||||||
* - Thread.sleep(...)
|
* - Thread.sleep(...)
|
||||||
* - obj.wait(...)
|
* - obj.wait(...)
|
||||||
* - some tests fail sporadically. typical workarounds are:
|
|
||||||
* - reconnect device
|
|
||||||
* - run test individually
|
|
||||||
* - increase sleep?
|
|
||||||
* - missing functionality on certain devices, see:
|
* - missing functionality on certain devices, see:
|
||||||
* - if(rfc2217_server_nonstandard_baudrates)
|
* - if(rfc2217_server_nonstandard_baudrates)
|
||||||
* - if(usbSerialDriver instanceof ...)
|
* - if(usbSerialDriver instanceof ...)
|
||||||
@ -33,10 +18,10 @@ import android.content.IntentFilter;
|
|||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
import android.hardware.usb.UsbDeviceConnection;
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
import android.hardware.usb.UsbManager;
|
import android.hardware.usb.UsbManager;
|
||||||
|
import android.os.Process;
|
||||||
import android.support.test.InstrumentationRegistry;
|
import android.support.test.InstrumentationRegistry;
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.os.Process;
|
|
||||||
|
|
||||||
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.Ch34xSerialDriver;
|
||||||
@ -79,12 +64,13 @@ import static org.junit.Assert.fail;
|
|||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class DeviceTest implements SerialInputOutputManager.Listener {
|
public class DeviceTest implements SerialInputOutputManager.Listener {
|
||||||
|
|
||||||
// configuration:
|
// testInstrumentationRunnerArguments configuration
|
||||||
private final static String rfc2217_server_host = "192.168.0.100";
|
private static String rfc2217_server_host;
|
||||||
private final static int rfc2217_server_port = 2217;
|
private static int rfc2217_server_port = 2217;
|
||||||
private final static boolean rfc2217_server_nonstandard_baudrates = false; // false on Windows, Raspi
|
private static boolean rfc2217_server_nonstandard_baudrates;
|
||||||
private final static boolean rfc2217_server_parity_mark_space = false; // false on Raspi
|
private static boolean rfc2217_server_parity_mark_space;
|
||||||
private final static int test_device_port = 0;
|
private static String test_device_driver;
|
||||||
|
private static int test_device_port;
|
||||||
|
|
||||||
private final static int TELNET_READ_WAIT = 500;
|
private final static int TELNET_READ_WAIT = 500;
|
||||||
private final static int USB_READ_WAIT = 500;
|
private final static int USB_READ_WAIT = 500;
|
||||||
@ -116,9 +102,15 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUpFixture() throws Exception {
|
public static void setUpFixture() throws Exception {
|
||||||
|
rfc2217_server_host = InstrumentationRegistry.getArguments().getString("rfc2217_server_host");
|
||||||
|
rfc2217_server_nonstandard_baudrates = Boolean.valueOf(InstrumentationRegistry.getArguments().getString("rfc2217_server_nonstandard_baudrates"));
|
||||||
|
rfc2217_server_parity_mark_space = Boolean.valueOf(InstrumentationRegistry.getArguments().getString("rfc2217_server_parity_mark_space"));
|
||||||
|
test_device_driver = InstrumentationRegistry.getArguments().getString("test_device_driver");
|
||||||
|
test_device_port = Integer.valueOf(InstrumentationRegistry.getArguments().getString("test_device_port","0"));
|
||||||
|
|
||||||
|
// postpone parts of fixture setup to first test, because exceptions are not reported for @BeforeClass
|
||||||
|
// and test terminates with misleading 'Empty test suite'
|
||||||
telnetClient = null;
|
telnetClient = null;
|
||||||
// postpone fixture setup to first test, because exceptions are not reported for @BeforeClass
|
|
||||||
// and test terminates with missleading 'Empty test suite'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setUpFixtureInt() throws Exception {
|
public static void setUpFixtureInt() throws Exception {
|
||||||
@ -150,11 +142,15 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
context = InstrumentationRegistry.getContext();
|
context = InstrumentationRegistry.getContext();
|
||||||
final UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
|
final UsbManager usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
|
||||||
List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(usbManager);
|
List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(usbManager);
|
||||||
assertEquals("no usb device found", 1, availableDrivers.size());
|
assertEquals("no USB device found", 1, availableDrivers.size());
|
||||||
usbSerialDriver = availableDrivers.get(0);
|
usbSerialDriver = availableDrivers.get(0);
|
||||||
|
if(test_device_driver != null) {
|
||||||
|
String driverName = usbSerialDriver.getClass().getSimpleName();
|
||||||
|
assertEquals(test_device_driver+"SerialDriver", driverName);
|
||||||
|
}
|
||||||
assertTrue( usbSerialDriver.getPorts().size() > test_device_port);
|
assertTrue( usbSerialDriver.getPorts().size() > test_device_port);
|
||||||
usbSerialPort = usbSerialDriver.getPorts().get(test_device_port);
|
usbSerialPort = usbSerialDriver.getPorts().get(test_device_port);
|
||||||
Log.i(TAG, "Using USB device "+ usbSerialDriver.getClass().getSimpleName());
|
Log.i(TAG, "Using USB device "+ usbSerialPort.toString()+" driver="+usbSerialDriver.getClass().getSimpleName());
|
||||||
isCp21xxRestrictedPort = usbSerialDriver instanceof Cp21xxSerialDriver && usbSerialDriver.getPorts().size()==2 && test_device_port == 1;
|
isCp21xxRestrictedPort = usbSerialDriver instanceof Cp21xxSerialDriver && usbSerialDriver.getPorts().size()==2 && test_device_port == 1;
|
||||||
|
|
||||||
if (!usbManager.hasPermission(usbSerialPort.getDriver().getDevice())) {
|
if (!usbManager.hasPermission(usbSerialPort.getDriver().getDevice())) {
|
||||||
@ -372,7 +368,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRunError(Exception e) {
|
public void onRunError(Exception e) {
|
||||||
assertTrue("usb connection lost", false);
|
fail("usb connection lost");
|
||||||
}
|
}
|
||||||
|
|
||||||
// clone of org.apache.commons.lang3.StringUtils.indexOfDifference + optional startpos
|
// clone of org.apache.commons.lang3.StringUtils.indexOfDifference + optional startpos
|
||||||
@ -401,6 +397,27 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void logDifference(final StringBuilder data, final StringBuilder expected) {
|
||||||
|
int datapos = indexOfDifference(data, expected);
|
||||||
|
int expectedpos = datapos;
|
||||||
|
while(datapos != -1) {
|
||||||
|
int nextexpectedpos = -1;
|
||||||
|
int nextdatapos = datapos + 2;
|
||||||
|
int len = -1;
|
||||||
|
if(nextdatapos + 10 < data.length()) { // try to sync data+expected, assuming that data is lost, but not corrupted
|
||||||
|
String nextsub = data.substring(nextdatapos, nextdatapos + 10);
|
||||||
|
nextexpectedpos = expected.indexOf(nextsub, expectedpos);
|
||||||
|
if(nextexpectedpos >= 0) {
|
||||||
|
len = nextexpectedpos - expectedpos - 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.i(TAG, "difference at " + datapos + " len " + len );
|
||||||
|
Log.d(TAG, " got " + data.substring(Math.max(datapos - 20, 0), Math.min(datapos + 20, data.length())));
|
||||||
|
Log.d(TAG, " expected " + expected.substring(Math.max(expectedpos - 20, 0), Math.min(expectedpos + 20, expected.length())));
|
||||||
|
datapos = indexOfDifference(data, expected, nextdatapos, nextexpectedpos);
|
||||||
|
expectedpos = nextexpectedpos + (datapos - nextdatapos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void baudRate() throws Exception {
|
public void baudRate() throws Exception {
|
||||||
@ -435,8 +452,8 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
; // todo: add range check in driver
|
; // todo: add range check in driver
|
||||||
else
|
else
|
||||||
fail("invalid baudrate 0");
|
fail("invalid baudrate 0");
|
||||||
} catch (java.io.IOException e) { // cp2105 second port
|
} catch (java.io.IOException ignored) { // cp2105 second port
|
||||||
} catch (java.lang.IllegalArgumentException e) {
|
} catch (java.lang.IllegalArgumentException ignored) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
usbParameters(0, 8, 1, UsbSerialPort.PARITY_NONE);
|
usbParameters(0, 8, 1, UsbSerialPort.PARITY_NONE);
|
||||||
@ -448,9 +465,9 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
; // todo: add range check in driver
|
; // todo: add range check in driver
|
||||||
else
|
else
|
||||||
fail("invalid baudrate 0");
|
fail("invalid baudrate 0");
|
||||||
} catch (java.lang.ArithmeticException e) { // ch340
|
} catch (java.lang.ArithmeticException ignored) { // ch340
|
||||||
} catch (java.io.IOException e) { // cp2105 second port
|
} catch (java.io.IOException ignored) { // cp2105 second port
|
||||||
} catch (java.lang.IllegalArgumentException e) {
|
} catch (java.lang.IllegalArgumentException ignored) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
usbParameters(1, 8, 1, UsbSerialPort.PARITY_NONE);
|
usbParameters(1, 8, 1, UsbSerialPort.PARITY_NONE);
|
||||||
@ -464,8 +481,8 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
;
|
;
|
||||||
else
|
else
|
||||||
fail("invalid baudrate 0");
|
fail("invalid baudrate 0");
|
||||||
} catch (java.io.IOException e) { // ch340
|
} catch (java.io.IOException ignored) { // ch340
|
||||||
} catch (java.lang.IllegalArgumentException e) {
|
} catch (java.lang.IllegalArgumentException ignored) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
usbParameters(2<<31, 8, 1, UsbSerialPort.PARITY_NONE);
|
usbParameters(2<<31, 8, 1, UsbSerialPort.PARITY_NONE);
|
||||||
@ -477,9 +494,9 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
;
|
;
|
||||||
else
|
else
|
||||||
fail("invalid baudrate 2^31");
|
fail("invalid baudrate 2^31");
|
||||||
} catch (java.lang.ArithmeticException e) { // ch340
|
} catch (java.lang.ArithmeticException ignored) { // ch340
|
||||||
} catch (java.io.IOException e) { // cp2105 second port
|
} catch (java.io.IOException ignored) { // cp2105 second port
|
||||||
} catch (java.lang.IllegalArgumentException e) {
|
} catch (java.lang.IllegalArgumentException ignored) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int baudRate : new int[] {300, 2400, 19200, 42000, 115200} ) {
|
for(int baudRate : new int[] {300, 2400, 19200, 42000, 115200} ) {
|
||||||
@ -488,8 +505,8 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
if(baudRate == 300 && isCp21xxRestrictedPort) {
|
if(baudRate == 300 && isCp21xxRestrictedPort) {
|
||||||
try {
|
try {
|
||||||
usbParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);
|
usbParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);
|
||||||
assertTrue(false);
|
fail("baudrate 300 on cp21xx restricted port");
|
||||||
} catch (java.io.IOException e) {
|
} catch (java.io.IOException ignored) {
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -498,10 +515,10 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
|
|
||||||
telnetWrite("net2usb".getBytes());
|
telnetWrite("net2usb".getBytes());
|
||||||
data = usbRead(7);
|
data = usbRead(7);
|
||||||
assertThat(String.valueOf(baudRate)+"/8N1", data, equalTo("net2usb".getBytes()));
|
assertThat(baudRate+"/8N1", data, equalTo("net2usb".getBytes()));
|
||||||
usbWrite("usb2net".getBytes());
|
usbWrite("usb2net".getBytes());
|
||||||
data = telnetRead(7);
|
data = telnetRead(7);
|
||||||
assertThat(String.valueOf(baudRate)+"/8N1", data, equalTo("usb2net".getBytes()));
|
assertThat(baudRate+"/8N1", data, equalTo("usb2net".getBytes()));
|
||||||
}
|
}
|
||||||
{ // non matching baud rate
|
{ // non matching baud rate
|
||||||
telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
|
telnetParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
|
||||||
@ -529,7 +546,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
; // todo: add range check in driver
|
; // todo: add range check in driver
|
||||||
else
|
else
|
||||||
fail("invalid databits "+i);
|
fail("invalid databits "+i);
|
||||||
} catch (java.lang.IllegalArgumentException e) {
|
} catch (java.lang.IllegalArgumentException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -607,7 +624,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
try {
|
try {
|
||||||
usbParameters(19200, 8, 1, i);
|
usbParameters(19200, 8, 1, i);
|
||||||
fail("invalid parity "+i);
|
fail("invalid parity "+i);
|
||||||
} catch (java.lang.IllegalArgumentException e) {
|
} catch (java.lang.IllegalArgumentException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(isCp21xxRestrictedPort) {
|
if(isCp21xxRestrictedPort) {
|
||||||
@ -616,9 +633,12 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
usbParameters(19200, 8, 1, UsbSerialPort.PARITY_ODD);
|
usbParameters(19200, 8, 1, UsbSerialPort.PARITY_ODD);
|
||||||
try {
|
try {
|
||||||
usbParameters(19200, 8, 1, UsbSerialPort.PARITY_MARK);
|
usbParameters(19200, 8, 1, UsbSerialPort.PARITY_MARK);
|
||||||
|
fail("parity mark");
|
||||||
|
} catch (java.lang.IllegalArgumentException ignored) {}
|
||||||
|
try {
|
||||||
usbParameters(19200, 8, 1, UsbSerialPort.PARITY_SPACE);
|
usbParameters(19200, 8, 1, UsbSerialPort.PARITY_SPACE);
|
||||||
} catch (java.lang.IllegalArgumentException e) {
|
fail("parity space");
|
||||||
}
|
} catch (java.lang.IllegalArgumentException ignored) {}
|
||||||
return;
|
return;
|
||||||
// test below not possible as it requires unsupported 7 dataBits
|
// test below not possible as it requires unsupported 7 dataBits
|
||||||
}
|
}
|
||||||
@ -701,12 +721,13 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
try {
|
try {
|
||||||
usbParameters(19200, 8, i, UsbSerialPort.PARITY_NONE);
|
usbParameters(19200, 8, i, UsbSerialPort.PARITY_NONE);
|
||||||
fail("invalid stopbits " + i);
|
fail("invalid stopbits " + i);
|
||||||
} catch (java.lang.IllegalArgumentException e) {
|
} catch (java.lang.IllegalArgumentException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usbSerialDriver instanceof CdcAcmSerialDriver) {
|
if (usbSerialDriver instanceof CdcAcmSerialDriver) {
|
||||||
// software based bridge in arduino_leonardo_bridge.ino is to slow, other devices might support it
|
usbParameters(19200, 8, UsbSerialPort.STOPBITS_2, UsbSerialPort.PARITY_NONE);
|
||||||
|
// software based bridge in arduino_leonardo_bridge.ino is to slow for real test, other devices might support it
|
||||||
} else {
|
} else {
|
||||||
// shift stopbits into next byte, by using different databits
|
// shift stopbits into next byte, by using different databits
|
||||||
// a - start bit (0)
|
// a - start bit (0)
|
||||||
@ -764,12 +785,12 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
probeTable.addProduct(usbSerialDriver.getDevice().getVendorId(), usbSerialDriver.getDevice().getProductId(), usbSerialDriver.getClass());
|
probeTable.addProduct(usbSerialDriver.getDevice().getVendorId(), usbSerialDriver.getDevice().getProductId(), usbSerialDriver.getClass());
|
||||||
availableDrivers = new UsbSerialProber(probeTable).findAllDrivers(usbManager);
|
availableDrivers = new UsbSerialProber(probeTable).findAllDrivers(usbManager);
|
||||||
assertEquals(1, availableDrivers.size());
|
assertEquals(1, availableDrivers.size());
|
||||||
assertEquals(true, availableDrivers.get(0).getClass() == usbSerialDriver.getClass());
|
assertEquals(availableDrivers.get(0).getClass(), usbSerialDriver.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
// data loss es expected, if data is not consumed fast enough
|
// provoke data loss, when data is not read fast enough
|
||||||
public void readBuffer() throws Exception {
|
public void readBufferOverflow() throws Exception {
|
||||||
if(usbSerialDriver instanceof CdcAcmSerialDriver)
|
if(usbSerialDriver instanceof CdcAcmSerialDriver)
|
||||||
telnetWriteDelay = 10; // arduino_leonardo_bridge.ino sends each byte in own USB packet, which is horribly slow
|
telnetWriteDelay = 10; // arduino_leonardo_bridge.ino sends each byte in own USB packet, which is horribly slow
|
||||||
usbParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE);
|
usbParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE);
|
||||||
@ -778,10 +799,10 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
StringBuilder expected = new StringBuilder();
|
StringBuilder expected = new StringBuilder();
|
||||||
StringBuilder data = new StringBuilder();
|
StringBuilder data = new StringBuilder();
|
||||||
final int maxWait = 2000;
|
final int maxWait = 2000;
|
||||||
int bufferSize = 0;
|
int bufferSize;
|
||||||
for(bufferSize = 8; bufferSize < (2<<15); bufferSize *= 2) {
|
for(bufferSize = 8; bufferSize < (2<<15); bufferSize *= 2) {
|
||||||
int linenr = 0;
|
int linenr;
|
||||||
String line;
|
String line="-";
|
||||||
expected.setLength(0);
|
expected.setLength(0);
|
||||||
data.setLength(0);
|
data.setLength(0);
|
||||||
|
|
||||||
@ -794,7 +815,7 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
}
|
}
|
||||||
usbReadBlock = false;
|
usbReadBlock = false;
|
||||||
|
|
||||||
// slowly write new data, until old data is comletely read from buffer and new data is received again
|
// slowly write new data, until old data is completely read from buffer and new data is received
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
for (; linenr < bufferSize/8 + maxWait/10 && !found; linenr++) {
|
for (; linenr < bufferSize/8 + maxWait/10 && !found; linenr++) {
|
||||||
line = String.format("%07d,", linenr);
|
line = String.format("%07d,", linenr);
|
||||||
@ -804,47 +825,38 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
data.append(new String(usbRead(0)));
|
data.append(new String(usbRead(0)));
|
||||||
found = data.toString().endsWith(line);
|
found = data.toString().endsWith(line);
|
||||||
}
|
}
|
||||||
if(!found) {
|
while(!found) {
|
||||||
// use waiting read to clear input queue, else next test would see unexpected data
|
// use waiting read to clear input queue, else next test would see unexpected data
|
||||||
byte[] rest = null;
|
byte[] rest = usbRead(-1);
|
||||||
while(rest==null || rest.length>0)
|
if(rest.length == 0)
|
||||||
rest = usbRead(-1);
|
fail("last line "+line+" not found");
|
||||||
fail("end not found");
|
data.append(new String(rest));
|
||||||
|
found = data.toString().endsWith(line);
|
||||||
}
|
}
|
||||||
if (data.length() != expected.length())
|
if (data.length() != expected.length())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
int pos = indexOfDifference(data, expected);
|
|
||||||
Log.i(TAG, "bufferSize " + bufferSize + ", first difference at " + pos);
|
logDifference(data, expected);
|
||||||
// actual values have large variance for same device, e.g.
|
|
||||||
// bufferSize 4096, first difference at 164
|
|
||||||
// bufferSize 64, first difference at 57
|
|
||||||
assertTrue(bufferSize > 16);
|
assertTrue(bufferSize > 16);
|
||||||
assertTrue(data.length() != expected.length());
|
assertTrue(data.length() != expected.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// this test can fail sporadically!
|
|
||||||
//
|
|
||||||
// Android is not a real time OS, so there is no guarantee that the usb thread is scheduled, or it might be blocked by Java garbage collection.
|
|
||||||
// The SerialInputOutputManager uses a buffer size of 4Kb. Reading of these blocks happen behind UsbRequest.queue / UsbDeviceConnection.requestWait
|
|
||||||
// The dump of data and error positions in logcat show, that data is lost somewhere in the UsbRequest handling,
|
|
||||||
// very likely when the individual 64 byte USB packets are not read fast enough, and the serial converter chip has to discard bytes.
|
|
||||||
//
|
|
||||||
// On some days SERIAL_INPUT_OUTPUT_MANAGER_THREAD_PRIORITY=THREAD_PRIORITY_URGENT_AUDIO reduced errors by factor 10, on other days it had no effect at all!
|
|
||||||
//
|
|
||||||
@Test
|
@Test
|
||||||
public void readSpeed() throws Exception {
|
public void readSpeed() throws Exception {
|
||||||
// see logcat for performance results
|
// see logcat for performance results
|
||||||
//
|
//
|
||||||
// CDC arduino_leonardo_bridge.ini has transfer speed ~ 100 byte/sec
|
// CDC arduino_leonardo_bridge.ini has transfer speed ~ 100 byte/sec
|
||||||
// all other devices are near physical limit with ~ 10-12k/sec
|
// all other devices are near physical limit with ~ 10-12k/sec
|
||||||
|
//
|
||||||
|
// readBufferOverflow provokes read errors, but they can also happen here where the data is actually read fast enough.
|
||||||
|
// Android is not a real time OS, so there is no guarantee that the USB thread is scheduled, or it might be blocked by Java garbage collection.
|
||||||
|
// Using SERIAL_INPUT_OUTPUT_MANAGER_THREAD_PRIORITY=THREAD_PRIORITY_URGENT_AUDIO sometimes reduced errors by factor 10, sometimes not at all!
|
||||||
|
//
|
||||||
int baudrate = 115200;
|
int baudrate = 115200;
|
||||||
usbParameters(baudrate, 8, 1, UsbSerialPort.PARITY_NONE);
|
usbParameters(baudrate, 8, 1, UsbSerialPort.PARITY_NONE);
|
||||||
telnetParameters(baudrate, 8, 1, UsbSerialPort.PARITY_NONE);
|
telnetParameters(baudrate, 8, 1, UsbSerialPort.PARITY_NONE);
|
||||||
|
|
||||||
// fails more likely with larger or unlimited (-1) write ahead
|
|
||||||
int writeSeconds = 5;
|
int writeSeconds = 5;
|
||||||
int writeAhead = 5*baudrate/10; // write ahead for another 5 second read
|
int writeAhead = 5*baudrate/10; // write ahead for another 5 second read
|
||||||
if(usbSerialDriver instanceof CdcAcmSerialDriver)
|
if(usbSerialDriver instanceof CdcAcmSerialDriver)
|
||||||
@ -874,45 +886,17 @@ public class DeviceTest implements SerialInputOutputManager.Listener {
|
|||||||
dlen = data.length();
|
dlen = data.length();
|
||||||
elen = expected.length();
|
elen = expected.length();
|
||||||
}
|
}
|
||||||
boolean found = false;
|
|
||||||
long maxwait = Math.max(1000, (expected.length() - data.length()) * 20000L / baudrate );
|
|
||||||
next = System.currentTimeMillis() + maxwait;
|
|
||||||
Log.d(TAG, "readSpeed: rest wait time " + maxwait + " for " + (expected.length() - data.length()) + " byte");
|
|
||||||
while(!found && System.currentTimeMillis() < next) {
|
|
||||||
data.append(new String(usbRead(0)));
|
|
||||||
found = data.toString().endsWith(line);
|
|
||||||
Thread.sleep(1);
|
|
||||||
}
|
|
||||||
//next = System.currentTimeMillis();
|
|
||||||
//Log.i(TAG, "readSpeed: t="+(next-begin)+", read="+(data.length()-dlen));
|
|
||||||
|
|
||||||
int errcnt = 0;
|
boolean found = false;
|
||||||
int errlen = 0;
|
while(!found) {
|
||||||
int datapos = indexOfDifference(data, expected);
|
// use waiting read to clear input queue, else next test would see unexpected data
|
||||||
int expectedpos = datapos;
|
byte[] rest = usbRead(-1);
|
||||||
while(datapos != -1) {
|
if(rest.length == 0)
|
||||||
errcnt += 1;
|
break;
|
||||||
int nextexpectedpos = -1;
|
data.append(new String(rest));
|
||||||
int nextdatapos = datapos + 2;
|
found = data.toString().endsWith(line);
|
||||||
int len = -1;
|
|
||||||
if(nextdatapos + 10 < data.length()) { // try to sync data+expected, assuming that data is lost, but not corrupted
|
|
||||||
String nextsub = data.substring(nextdatapos, nextdatapos + 10);
|
|
||||||
nextexpectedpos = expected.indexOf(nextsub, expectedpos);
|
|
||||||
if(nextexpectedpos >= 0) {
|
|
||||||
len = nextexpectedpos - expectedpos - 2;
|
|
||||||
errlen += len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Log.i(TAG, "readSpeed: difference at " + datapos + " len " + len );
|
|
||||||
Log.d(TAG, "readSpeed: got " + data.substring(Math.max(datapos - 20, 0), Math.min(datapos + 20, data.length())));
|
|
||||||
Log.d(TAG, "readSpeed: expected " + expected.substring(Math.max(expectedpos - 20, 0), Math.min(expectedpos + 20, expected.length())));
|
|
||||||
datapos = indexOfDifference(data, expected, nextdatapos, nextexpectedpos);
|
|
||||||
expectedpos = nextexpectedpos + (datapos - nextdatapos);
|
|
||||||
}
|
}
|
||||||
if(errcnt != 0)
|
logDifference(data, expected);
|
||||||
Log.i(TAG, "readSpeed: got " + errcnt + " errors, total len " + errlen+ ", avg. len " + errlen/errcnt);
|
|
||||||
assertTrue("end not found", found);
|
|
||||||
assertEquals("no errors", 0, errcnt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
x
Reference in New Issue
Block a user