Skip to content

Commit 06faad5

Browse files
committed
CDC device tests with MCP2221
1 parent 52042f8 commit 06faad5

File tree

4 files changed

+123
-128
lines changed

4 files changed

+123
-128
lines changed

.idea/AndroidProjectSystem.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

usbSerialForAndroid/coverage.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ android {
88
// Used as fallback in usbSerialExample/build.gradle -> missingDimensionStrategy, but not for coverage report
99
dimension 'device'
1010
}
11-
arduino {
11+
mcp2221 {
1212
dimension 'device'
1313
testInstrumentationRunnerArguments = ['test_device_driver': 'CdcAcm']
1414
}

usbSerialForAndroid/src/androidTest/java/com/hoho/android/usbserial/DeviceTest.java

Lines changed: 115 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,13 @@ public void dataBits() throws Exception {
645645
Thread.sleep(10);
646646
usb.write(new byte[]{(byte) 0xff});
647647
data = telnet.read(2);
648-
assertThat("19000/7N1", data, equalTo(new byte[]{(byte) 0x80, (byte) 0xff}));
648+
if(usb.serialDriver instanceof CdcAcmSerialDriver) {
649+
// not supported by MCP2221, other CDC devices might support it
650+
assertThat("19000/7N1", data, equalTo(new byte[]{(byte) 0x00, (byte) 0xff}));
651+
return;
652+
} else {
653+
assertThat("19000/7N1", data, equalTo(new byte[]{(byte) 0x80, (byte) 0xff}));
654+
}
649655
} catch (UnsupportedOperationException e) {
650656
if(!usb.isCp21xxRestrictedPort)
651657
throw e;
@@ -718,18 +724,17 @@ public void parity() throws Exception {
718724
usb.setParameters(19200, 7, 1, UsbSerialPort.PARITY_ODD);
719725
usb.write(_8n1);
720726
data = telnet.read(4);
721-
assertThat("19200/7O1", data, equalTo(_7o1));
722-
723-
usb.setParameters(19200, 7, 1, UsbSerialPort.PARITY_EVEN);
724-
usb.write(_8n1);
725-
data = telnet.read(4);
726-
assertThat("19200/7E1", data, equalTo(_7e1));
727-
728727
if (usb.serialDriver instanceof CdcAcmSerialDriver) {
729-
// not supported by arduino_leonardo_bridge.ino, other devices might support it
730-
usb.setParameters(19200, 7, 1, UsbSerialPort.PARITY_MARK);
731-
usb.setParameters(19200, 7, 1, UsbSerialPort.PARITY_SPACE);
728+
// not supported by MCP2221, other CDC devices might support it
729+
assertThat("19200/8N1", data, equalTo(_8n1));
732730
} else {
731+
assertThat("19200/7O1", data, equalTo(_7o1));
732+
733+
usb.setParameters(19200, 7, 1, UsbSerialPort.PARITY_EVEN);
734+
usb.write(_8n1);
735+
data = telnet.read(4);
736+
assertThat("19200/7E1", data, equalTo(_7e1));
737+
733738
usb.setParameters(19200, 7, 1, UsbSerialPort.PARITY_MARK);
734739
usb.write(_8n1);
735740
data = telnet.read(4);
@@ -758,19 +763,19 @@ public void parity() throws Exception {
758763
data = usb.read(4);
759764
assertThat("19200/7E1", data, equalTo(_7e1));
760765

761-
if (usb.serialDriver instanceof CdcAcmSerialDriver) {
762-
// not supported by arduino_leonardo_bridge.ino, other devices might support it
763-
} else {
764-
telnet.setParameters(19200, 7, 1, UsbSerialPort.PARITY_MARK);
765-
telnet.write(_8n1);
766-
data = usb.read(4);
767-
assertThat("19200/7M1", data, equalTo(_7m1));
766+
telnet.setParameters(19200, 7, 1, UsbSerialPort.PARITY_MARK);
767+
telnet.write(_8n1);
768+
data = usb.read(4);
769+
assertThat("19200/7M1", data, equalTo(_7m1));
768770

769-
telnet.setParameters(19200, 7, 1, UsbSerialPort.PARITY_SPACE);
770-
telnet.write(_8n1);
771-
data = usb.read(4);
772-
assertThat("19200/7S1", data, equalTo(_7s1));
771+
telnet.setParameters(19200, 7, 1, UsbSerialPort.PARITY_SPACE);
772+
telnet.write(_8n1);
773+
data = usb.read(4);
774+
assertThat("19200/7S1", data, equalTo(_7s1));
773775

776+
if (usb.serialDriver instanceof CdcAcmSerialDriver) {
777+
; // not supported by MCP2221, other CDC devices might support it
778+
} else {
774779
usb.setParameters(19200, 7, 1, UsbSerialPort.PARITY_ODD);
775780
telnet.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
776781
telnet.write(_8n1);
@@ -792,45 +797,44 @@ public void stopBits() throws Exception {
792797
}
793798
}
794799

800+
// shift stopbits into next byte, by using different databits
801+
// a - start bit (0)
802+
// o - stop bit (1)
803+
// d - data bit
804+
805+
// out 8N2: addddddd doaddddddddo
806+
// 1000001 0 10001111
807+
// in 6N1: addddddo addddddo
808+
// 100000 101000
809+
usb.setParameters(19200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
810+
telnet.setParameters(19200, 6, 1, UsbSerialPort.PARITY_NONE);
811+
usb.write(new byte[]{(byte)0x41, (byte)0xf1});
812+
data = telnet.read(2);
795813
if (usb.serialDriver instanceof CdcAcmSerialDriver) {
796-
usb.setParameters(19200, 8, UsbSerialPort.STOPBITS_1_5, UsbSerialPort.PARITY_NONE);
797-
// software based bridge in arduino_leonardo_bridge.ino is to slow for real test, other devices might support it
798-
} else {
799-
// shift stopbits into next byte, by using different databits
800-
// a - start bit (0)
801-
// o - stop bit (1)
802-
// d - data bit
803-
804-
// out 8N2: addddddd doaddddddddo
805-
// 1000001 0 10001111
806-
// in 6N1: addddddo addddddo
807-
// 100000 101000
808-
usb.setParameters(19200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
809-
telnet.setParameters(19200, 6, 1, UsbSerialPort.PARITY_NONE);
810-
usb.write(new byte[]{(byte)0x41, (byte)0xf1});
811-
data = telnet.read(2);
814+
// MCP2221 slightly slower, looks like 2 stop bits. could be different for other CDC devices
815+
assertThat("19200/8N1", data, equalTo(new byte[]{1, 11}));
816+
} else
812817
assertThat("19200/8N1", data, equalTo(new byte[]{1, 5}));
813818

814-
// out 8N2: addddddd dooaddddddddoo
815-
// 1000001 0 10011111
816-
// in 6N1: addddddo addddddo
817-
// 100000 110100
818-
try {
819-
usb.setParameters(19200, 8, UsbSerialPort.STOPBITS_2, UsbSerialPort.PARITY_NONE);
820-
telnet.setParameters(19200, 6, 1, UsbSerialPort.PARITY_NONE);
821-
usb.write(new byte[]{(byte) 0x41, (byte) 0xf9});
822-
data = telnet.read(2);
823-
assertThat("19200/8N1", data, equalTo(new byte[]{1, 11}));
824-
} catch(UnsupportedOperationException e) {
825-
if(!usb.isCp21xxRestrictedPort)
826-
throw e;
827-
}
828-
try {
829-
usb.setParameters(19200, 8, UsbSerialPort.STOPBITS_1_5, UsbSerialPort.PARITY_NONE);
830-
// todo: could create similar test for 1.5 stopbits, by reading at double speed
831-
// but only some devices support 1.5 stopbits and it is basically not used any more
832-
} catch(UnsupportedOperationException ignored) {
833-
}
819+
// out 8N2: addddddd dooaddddddddoo
820+
// 1000001 0 10011111
821+
// in 6N1: addddddo addddddo
822+
// 100000 110100
823+
try {
824+
usb.setParameters(19200, 8, UsbSerialPort.STOPBITS_2, UsbSerialPort.PARITY_NONE);
825+
telnet.setParameters(19200, 6, 1, UsbSerialPort.PARITY_NONE);
826+
usb.write(new byte[]{(byte) 0x41, (byte) 0xf9});
827+
data = telnet.read(2);
828+
assertThat("19200/8N1", data, equalTo(new byte[]{1, 11}));
829+
} catch(UnsupportedOperationException e) {
830+
if(!usb.isCp21xxRestrictedPort)
831+
throw e;
832+
}
833+
try {
834+
usb.setParameters(19200, 8, UsbSerialPort.STOPBITS_1_5, UsbSerialPort.PARITY_NONE);
835+
// todo: could create similar test for 1.5 stopbits, by reading at double speed
836+
// but only some devices support 1.5 stopbits and it is basically not used any more
837+
} catch(UnsupportedOperationException ignored) {
834838
}
835839
}
836840

@@ -883,8 +887,6 @@ public void writeSizes() throws Exception {
883887
usb.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);
884888
telnet.setParameters(baudRate, 8, 1, UsbSerialPort.PARITY_NONE);
885889
int purgeTimeout = 250;
886-
if(usb.serialDriver instanceof CdcAcmSerialDriver)
887-
purgeTimeout = 500;
888890
purgeWriteBuffer(purgeTimeout);
889891

890892
// determine write buffer size
@@ -1055,18 +1057,17 @@ public void writeFragments() throws Exception {
10551057

10561058
@Test
10571059
public void readBufferSize() throws Exception {
1058-
// looks like devices perform USB read with full mReadEndpoint.getMaxPacketSize() size (32, 64, 512)
1060+
// looks like devices perform USB read with full mReadEndpoint.getMaxPacketSize() size (16, 32, 64, 512)
10591061
// if the buffer is smaller than the received result, it is silently lost
10601062
//
10611063
// for buffer > packet size, but not multiple of packet size, the same issue happens, but typically
10621064
// only the last (partly filled) packet is lost.
1063-
if(usb.serialDriver instanceof CdcAcmSerialDriver)
1064-
return; // arduino sends each byte individually, so not testable here
10651065
byte[] data;
10661066
boolean purge = true;
10671067

10681068
usb.open(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_IOMANAGER_START));
1069-
usb.ioManager.setReadBufferSize(8);
1069+
int len = Math.min(16, usb.serialPort.getReadEndpoint().getMaxPacketSize()/2); // 8 for MCP2221, else 16
1070+
usb.ioManager.setReadBufferSize(len/2);
10701071
usb.ioManager.start();
10711072
usb.setParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE);
10721073
telnet.setParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE);
@@ -1075,13 +1076,15 @@ public void readBufferSize() throws Exception {
10751076
telnet.write("1aaa".getBytes());
10761077
data = usb.read(4);
10771078
assertThat(data, equalTo("1aaa".getBytes()));
1078-
telnet.write(new byte[16]);
1079+
1080+
telnet.write(new byte[len]);
10791081
try {
1080-
data = usb.read(16);
1082+
data = usb.read(len);
10811083
if (usb.serialDriver instanceof Cp21xxSerialDriver && usb.serialDriver.getPorts().size() == 1)
10821084
assertNotEquals(0, data.length); // can be shorter or full length
1083-
else if (usb.serialDriver instanceof ProlificSerialDriver)
1084-
assertTrue("expected > 0 and < 16 byte, got " + data.length, data.length > 0 && data.length < 16);
1085+
else if (usb.serialDriver instanceof CdcAcmSerialDriver ||
1086+
usb.serialDriver instanceof ProlificSerialDriver)
1087+
assertTrue("expected > 0 and < "+len+" byte, got " + data.length, data.length > 0 && data.length < len);
10851088
else // ftdi, ch340, cp2105
10861089
assertEquals(0, data.length);
10871090
} catch (IOException ignored) {
@@ -1121,12 +1124,13 @@ else if (usb.serialDriver instanceof ProlificSerialDriver)
11211124
telnet.write("2aaa".getBytes());
11221125
data = usb.read(4, 8);
11231126
assertThat(data, equalTo("2aaa".getBytes()));
1124-
telnet.write(new byte[16]);
1125-
data = usb.read(16, 8);
1127+
telnet.write(new byte[len]);
1128+
data = usb.read(len, len/2);
11261129
if (usb.serialDriver instanceof Cp21xxSerialDriver && usb.serialDriver.getPorts().size() == 1)
11271130
assertNotEquals(0, data.length); // can be shorter or full length
1128-
else if (usb.serialDriver instanceof ProlificSerialDriver)
1129-
assertTrue("sporadic issue! expected > 0 and < 16 byte, got " + data.length, data.length > 0 && data.length < 16);
1131+
else if (usb.serialDriver instanceof CdcAcmSerialDriver ||
1132+
usb.serialDriver instanceof ProlificSerialDriver)
1133+
assertTrue("sporadic issue! expected > 0 and < "+len+" byte, got " + data.length, data.length > 0 && data.length < len);
11301134
else // ftdi, ch340, cp2105
11311135
assertEquals(0, data.length);
11321136
telnet.write("2ccc".getBytes());
@@ -1146,8 +1150,6 @@ else if (usb.serialDriver instanceof ProlificSerialDriver)
11461150
@Test
11471151
// provoke data loss, when data is not read fast enough
11481152
public void readBufferOverflow() throws Exception {
1149-
if(usb.serialDriver instanceof CdcAcmSerialDriver)
1150-
telnet.writeDelay = 10; // arduino_leonardo_bridge.ino sends each byte in own USB packet, which is horribly slow
11511153
usb.open();
11521154
usb.setParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE);
11531155
telnet.setParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE);
@@ -1220,8 +1222,6 @@ private int readSpeedInt(int writeSeconds, int readBufferSize, int readTimeout)
12201222
if(usb.serialDriver instanceof Ch34xSerialDriver)
12211223
baudrate = 38400;
12221224
int writeAhead = 5*baudrate/10; // write ahead for another 5 second read
1223-
if(usb.serialDriver instanceof CdcAcmSerialDriver)
1224-
writeAhead = 50;
12251225

12261226
usb.open(EnumSet.of(UsbWrapper.OpenCloseFlags.NO_IOMANAGER_START));
12271227
usb.ioManager.setReadTimeout(readTimeout);
@@ -1270,16 +1270,10 @@ private int readSpeedInt(int writeSeconds, int readBufferSize, int readTimeout)
12701270

12711271
@Test
12721272
public void writeSpeed() throws Exception {
1273-
// see logcat for performance results
1274-
//
1275-
// CDC arduino_leonardo_bridge.ino has transfer speed ~ 100 byte/sec
1276-
// all other devices can get near physical limit:
1277-
// longlines=true:, speed is near physical limit at 11.5k
1278-
// longlines=false: speed is 3-4k for all devices, as more USB packets are required
1273+
// see logcat for performance results, speed is near physical limit at 11.5k
12791274
usb.open();
12801275
usb.setParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE);
12811276
telnet.setParameters(115200, 8, 1, UsbSerialPort.PARITY_NONE);
1282-
boolean longlines = !(usb.serialDriver instanceof CdcAcmSerialDriver);
12831277

12841278
int linenr = 0;
12851279
String line="";
@@ -1292,10 +1286,7 @@ public void writeSpeed() throws Exception {
12921286
for(int seconds=1; seconds<=5; seconds++) {
12931287
next += 1000;
12941288
while (System.currentTimeMillis() < next) {
1295-
if(longlines)
1296-
line = String.format("%060d,", linenr++);
1297-
else
1298-
line = String.format("%07d,", linenr++);
1289+
line = String.format("%060d,", linenr++);
12991290
usb.write(line.getBytes());
13001291
expected.append(line);
13011292
data.append(new String(telnet.read(0)));
@@ -1576,34 +1567,32 @@ public void readTimeout() throws Exception {
15761567
}
15771568
Log.i(TAG, "average time per read " + (System.currentTimeMillis()-time)/i + " msec");
15781569

1579-
if(!(usb.serialDriver instanceof CdcAcmSerialDriver)) {
1580-
int diffLen;
1581-
usb.close();
1582-
// no issue with high transfer rate and long read timeout
1583-
diffLen = readSpeedInt(5, -1, longTimeout);
1584-
if(usb.serialDriver instanceof Ch34xSerialDriver && diffLen == -1)
1585-
diffLen = 0; // todo: investigate last packet loss
1586-
assertEquals(0, diffLen);
1587-
usb.close();
1588-
// date loss with high transfer rate and short read timeout !!!
1589-
diffLen = readSpeedInt(5, -1, shortTimeout);
1590-
1591-
assertNotEquals("sporadic issue!", 0, diffLen);
1592-
1593-
// data loss observed with read timeout up to 200 msec, e.g.
1594-
// difference at 181 len 64
1595-
// got 000020,0000021,0000030,0000031,0000032,0
1596-
// expected 000020,0000021,0000022,0000023,0000024,0
1597-
// difference at 341 len 128
1598-
// got 000048,0000049,0000066,0000067,0000068,0
1599-
// expected 000048,0000049,0000050,0000051,0000052,0
1600-
// difference at 724 len 704
1601-
// got 0000112,0000113,0000202,0000203,0000204,
1602-
// expected 0000112,0000113,0000114,0000115,0000116,
1603-
// difference at 974 len 8
1604-
// got 00231,0000232,0000234,0000235,0000236,00
1605-
// expected 00231,0000232,0000233,0000234,0000235,00
1606-
}
1570+
int diffLen;
1571+
usb.close();
1572+
// no issue with high transfer rate and long read timeout
1573+
diffLen = readSpeedInt(5, -1, longTimeout);
1574+
if(usb.serialDriver instanceof Ch34xSerialDriver && diffLen == -1)
1575+
diffLen = 0; // todo: investigate last packet loss
1576+
assertEquals(0, diffLen);
1577+
usb.close();
1578+
// date loss with high transfer rate and short read timeout !!!
1579+
diffLen = readSpeedInt(5, -1, shortTimeout);
1580+
1581+
assertNotEquals("sporadic issue!", 0, diffLen);
1582+
1583+
// data loss observed with read timeout up to 200 msec, e.g.
1584+
// difference at 181 len 64
1585+
// got 000020,0000021,0000030,0000031,0000032,0
1586+
// expected 000020,0000021,0000022,0000023,0000024,0
1587+
// difference at 341 len 128
1588+
// got 000048,0000049,0000066,0000067,0000068,0
1589+
// expected 000048,0000049,0000050,0000051,0000052,0
1590+
// difference at 724 len 704
1591+
// got 0000112,0000113,0000202,0000203,0000204,
1592+
// expected 0000112,0000113,0000114,0000115,0000116,
1593+
// difference at 974 len 8
1594+
// got 00231,0000232,0000234,0000235,0000236,00
1595+
// expected 00231,0000232,0000233,0000234,0000235,00
16071596
}
16081597

16091598
@Test
@@ -1808,12 +1797,7 @@ public void controlLines() throws Exception {
18081797
assertThat(usb.getControlLine(usb.serialPort::getCD), equalTo(inputLineFalse));
18091798
assertThat(usb.getControlLine(usb.serialPort::getRI), equalTo(usb.inputLinesOnlyRtsCts ? Boolean.FALSE : inputLineTrue));
18101799
telnet.write(data);
1811-
if(usb.serialDriver instanceof CdcAcmSerialDriver)
1812-
// arduino: control line feedback as serial_state notification is not implemented.
1813-
// It does not send w/o RTS or DTR, so these control lines can be partly checked here.
1814-
assertEquals(0, usb.read().length);
1815-
else
1816-
assertThat(Arrays.toString(data), usb.read(4), equalTo(data));
1800+
assertThat(Arrays.toString(data), usb.read(4), equalTo(data));
18171801
usb.write(data);
18181802
assertThat(Arrays.toString(data), telnet.read(4), equalTo(data));
18191803

@@ -2312,20 +2296,25 @@ void run() throws Exception {
23122296
@Test
23132297
public void setBreak() throws Exception {
23142298
usb.open();
2299+
if (usb.serialDriver instanceof CdcAcmSerialDriver) {
2300+
// not supported by MCP2221, other CDC devices might support it
2301+
try {
2302+
usb.serialPort.setBreak(true);
2303+
fail("setBreak error expected");
2304+
} catch (IOException ignored) {
2305+
}
2306+
return;
2307+
}
23152308
telnet.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
23162309
usb.setParameters(19200, 8, 1, UsbSerialPort.PARITY_NONE);
23172310
doReadWrite("");
2318-
usb.serialPort.setBreak(true);
23192311
Thread.sleep(100);
23202312
usb.serialPort.setBreak(false);
23212313
// RFC2217 has SET_CONTROL + REQ_BREAK_STATE request, but this is not supported by pyserial
23222314
// as there is no easy notification on <break> condition. By default break is returned as
23232315
// 0 byte on Linux, see https://man7.org/linux/man-pages/man3/termios.3.html -> BRKINT
23242316
byte[] data = telnet.read(1);
2325-
if (usb.serialDriver instanceof CdcAcmSerialDriver) {
2326-
// BREAK forwarding not implemented by arduino_leonardo_bridge.ino
2327-
assertThat("<break>", data, equalTo(new byte[]{}));
2328-
} else if(usb.isCp21xxRestrictedPort) {
2317+
if(usb.isCp21xxRestrictedPort) {
23292318
assertThat("<break>", data, equalTo(new byte[]{0x55})); // send the last byte again?
23302319
} else {
23312320
assertThat("<break>", data, equalTo(new byte[]{0}));

0 commit comments

Comments
 (0)