Skip to content

Commit f761bb9

Browse files
Filip Jagodzinskic1728p9
authored andcommitted
Tests: USB: DTR fix for Linux hosts
A DTR line is used to signal that the host has configured a terminal and is ready to transmit and receive data from the USB CDC/Serial device. When this test suite is run with the use of a Linux host, a workaround has to be used to overcome some platform specific DTR line behavior. Every time the serial port file descriptor is opened, the DTR line is asserted until the terminal attributes are set. As a consequence, the device receives a premature DTR signal with a duration of 200-500 us before the correct, long-lasting DTR signal set by the host-side test script. (tested on the Linux kernel 4.15.0) The solution is to wait for the first DTR spike, ignore it, and wait for the correct DTR signal again.
1 parent 130f302 commit f761bb9

File tree

2 files changed

+90
-17
lines changed

2 files changed

+90
-17
lines changed

TESTS/host_tests/usb_device_serial.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def __init__(self):
128128

129129
def port_open_wait(self):
130130
"""Open the serial and wait until it's closed by the device."""
131-
mbed_serial = serial.Serial()
131+
mbed_serial = serial.Serial(dsrdtr=False)
132132
mbed_serial.dtr = False
133133
try:
134134
mbed_serial.port = retry_fun_call(
@@ -139,19 +139,20 @@ def port_open_wait(self):
139139
fun=mbed_serial.open,
140140
num_retries=20,
141141
retry_delay=0.05)
142-
mbed_serial.dtr = True
143-
try:
144-
mbed_serial.read() # wait until closed
145-
except (serial.portNotOpenError, serial.SerialException):
146-
pass
147142
except RetryError as exc:
148143
self.log('TEST ERROR: {}'.format(exc))
149144
self.notify_complete(False)
150145
return
146+
mbed_serial.dtr = True
147+
try:
148+
mbed_serial.read() # wait until closed
149+
except (serial.portNotOpenError, serial.SerialException):
150+
pass
151151

152152
def port_open_close(self):
153153
"""Open the serial and close it with a delay."""
154-
mbed_serial = serial.Serial(timeout=0.5, write_timeout=0.1)
154+
mbed_serial = serial.Serial(timeout=0.5, write_timeout=0.1, dsrdtr=False)
155+
mbed_serial.dtr = False
155156
try:
156157
mbed_serial.port = retry_fun_call(
157158
fun=functools.partial(self.get_usb_serial_name, self.dut_usb_dev_sn), # pylint: disable=not-callable
@@ -161,22 +162,22 @@ def port_open_close(self):
161162
fun=mbed_serial.open,
162163
num_retries=20,
163164
retry_delay=0.05)
164-
mbed_serial.reset_output_buffer()
165-
mbed_serial.dtr = True
166-
time.sleep(TERM_REOPEN_DELAY)
167-
mbed_serial.close()
168165
except RetryError as exc:
169166
self.log('TEST ERROR: {}'.format(exc))
170167
self.notify_complete(False)
171168
return
169+
mbed_serial.reset_output_buffer()
170+
mbed_serial.dtr = True
171+
time.sleep(TERM_REOPEN_DELAY)
172+
mbed_serial.close()
172173

173174
def send_data_sequence(self, chunk_size=1):
174175
"""Open the serial and send a sequence of values.
175176
176177
chunk_size defines the size of data sent in each write operation.
177178
The input buffer content is discarded.
178179
"""
179-
mbed_serial = serial.Serial(write_timeout=0.1)
180+
mbed_serial = serial.Serial(write_timeout=0.1, dsrdtr=False)
180181
try:
181182
mbed_serial.port = retry_fun_call(
182183
fun=functools.partial(self.get_usb_serial_name, self.dut_usb_dev_sn), # pylint: disable=not-callable
@@ -211,7 +212,7 @@ def send_data_sequence(self, chunk_size=1):
211212

212213
def loopback(self):
213214
"""Open the serial and send back every byte received."""
214-
mbed_serial = serial.Serial(timeout=0.5, write_timeout=0.1)
215+
mbed_serial = serial.Serial(timeout=0.5, write_timeout=0.1, dsrdtr=False)
215216
mbed_serial.dtr = False
216217
try:
217218
mbed_serial.port = retry_fun_call(
@@ -248,7 +249,7 @@ def change_line_coding(self):
248249
249250
New line coding params are read from the device serial data.
250251
"""
251-
mbed_serial = serial.Serial(timeout=0.5)
252+
mbed_serial = serial.Serial(timeout=0.5, dsrdtr=False)
252253
mbed_serial.dtr = False
253254
try:
254255
mbed_serial.port = retry_fun_call(

TESTS/usb_device/serial/main.cpp

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,24 @@
5252
// This way the device has to correctly handle data bigger that its buffer.
5353
#define HOST_RX_BUFF_SIZE_RATIO 64
5454

55+
// A DTR line is used to signal that the host has configured a terminal and
56+
// is ready to transmit and receive data from the USB CDC/Serial device.
57+
// When this test suite is run with the use of a Linux host, a workaround has
58+
// to be used to overcome some platform specific DTR line behavior.
59+
// Every time the serial port file descriptor is opened, the DTR line is
60+
// asserted until the terminal attributes are set.
61+
// As a consequence, the device receives a premature DTR signal with a
62+
// duration of 200-500 us before the correct, long-lasting DTR signal set by
63+
// the host-side test script. (tested on the Linux kernel 4.15.0)
64+
//
65+
// Online references:
66+
// https://github.com/pyserial/pyserial/issues/124#issuecomment-227235402
67+
//
68+
// The solution is to wait for the first DTR spike, ignore it, and wait for
69+
// the correct DTR signal again.
70+
#define LINUX_HOST_DTR_FIX 1
71+
#define LINUX_HOST_DTR_FIX_DELAY_MS 1
72+
5573
#define CDC_LOOPBACK_REPS 1200
5674
#define SERIAL_LOOPBACK_REPS 100
5775
#define USB_RECONNECT_DELAY_MS 1
@@ -275,6 +293,10 @@ void test_cdc_usb_reconnect()
275293

276294
greentea_send_kv(MSG_KEY_PORT_OPEN_WAIT, MSG_VALUE_DUMMY);
277295
// Wait for the host to open the port.
296+
#if LINUX_HOST_DTR_FIX
297+
usb_cdc.wait_ready();
298+
wait_ms(LINUX_HOST_DTR_FIX_DELAY_MS);
299+
#endif
278300
usb_cdc.wait_ready();
279301
TEST_ASSERT_TRUE(usb_cdc.configured());
280302
TEST_ASSERT_TRUE(usb_cdc.ready());
@@ -296,6 +318,10 @@ void test_cdc_usb_reconnect()
296318

297319
greentea_send_kv(MSG_KEY_PORT_OPEN_WAIT, MSG_VALUE_DUMMY);
298320
// Wait for the host to open the port again.
321+
#if LINUX_HOST_DTR_FIX
322+
usb_cdc.wait_ready();
323+
wait_ms(LINUX_HOST_DTR_FIX_DELAY_MS);
324+
#endif
299325
usb_cdc.wait_ready();
300326
TEST_ASSERT_TRUE(usb_cdc.configured());
301327
TEST_ASSERT_TRUE(usb_cdc.ready());
@@ -317,6 +343,10 @@ void test_cdc_rx_single_bytes()
317343
TestUSBCDC usb_cdc(USB_CDC_VID, USB_CDC_PID, 1, usb_dev_sn);
318344
usb_cdc.connect();
319345
greentea_send_kv(MSG_KEY_SEND_BYTES_SINGLE, MSG_VALUE_DUMMY);
346+
#if LINUX_HOST_DTR_FIX
347+
usb_cdc.wait_ready();
348+
wait_ms(LINUX_HOST_DTR_FIX_DELAY_MS);
349+
#endif
320350
usb_cdc.wait_ready();
321351
uint8_t buff = 0x01;
322352
for (int expected = 0xff; expected >= 0; expected--) {
@@ -360,6 +390,10 @@ void test_cdc_rx_single_bytes_concurrent()
360390
TestUSBCDC usb_cdc(USB_CDC_VID, USB_CDC_PID, 1, usb_dev_sn);
361391
usb_cdc.connect();
362392
greentea_send_kv(MSG_KEY_SEND_BYTES_SINGLE, MSG_VALUE_DUMMY);
393+
#if LINUX_HOST_DTR_FIX
394+
usb_cdc.wait_ready();
395+
wait_ms(LINUX_HOST_DTR_FIX_DELAY_MS);
396+
#endif
363397
usb_cdc.wait_ready();
364398
Thread tx_thread;
365399
event_flags.set(EF_SEND);
@@ -393,6 +427,10 @@ void test_cdc_rx_multiple_bytes()
393427
TestUSBCDC usb_cdc(USB_CDC_VID, USB_CDC_PID, 1, usb_dev_sn);
394428
usb_cdc.connect();
395429
greentea_send_kv(MSG_KEY_SEND_BYTES_MULTIPLE, HOST_RX_BUFF_SIZE_RATIO);
430+
#if LINUX_HOST_DTR_FIX
431+
usb_cdc.wait_ready();
432+
wait_ms(LINUX_HOST_DTR_FIX_DELAY_MS);
433+
#endif
396434
usb_cdc.wait_ready();
397435
uint8_t buff[RX_BUFF_SIZE] = { 0 };
398436
uint8_t expected_buff[RX_BUFF_SIZE] = { 0 };
@@ -429,6 +467,10 @@ void test_cdc_rx_multiple_bytes_concurrent()
429467
TestUSBCDC usb_cdc(USB_CDC_VID, USB_CDC_PID, 1, usb_dev_sn);
430468
usb_cdc.connect();
431469
greentea_send_kv(MSG_KEY_SEND_BYTES_MULTIPLE, HOST_RX_BUFF_SIZE_RATIO);
470+
#if LINUX_HOST_DTR_FIX
471+
usb_cdc.wait_ready();
472+
wait_ms(LINUX_HOST_DTR_FIX_DELAY_MS);
473+
#endif
432474
usb_cdc.wait_ready();
433475
Thread tx_thread;
434476
event_flags.set(EF_SEND);
@@ -470,6 +512,10 @@ void test_cdc_loopback()
470512
TestUSBCDC usb_cdc(USB_CDC_VID, USB_CDC_PID, 1, usb_dev_sn);
471513
usb_cdc.connect();
472514
greentea_send_kv(MSG_KEY_LOOPBACK, MSG_VALUE_DUMMY);
515+
#if LINUX_HOST_DTR_FIX
516+
usb_cdc.wait_ready();
517+
wait_ms(LINUX_HOST_DTR_FIX_DELAY_MS);
518+
#endif
473519
usb_cdc.wait_ready();
474520
uint8_t rx_buff, tx_buff;
475521
for (int i = 0; i < CDC_LOOPBACK_REPS; i++) {
@@ -511,6 +557,10 @@ void test_serial_usb_reconnect()
511557

512558
greentea_send_kv(MSG_KEY_PORT_OPEN_WAIT, MSG_VALUE_DUMMY);
513559
// Wait for the host to open the port.
560+
#if LINUX_HOST_DTR_FIX
561+
usb_serial.wait_ready();
562+
wait_ms(LINUX_HOST_DTR_FIX_DELAY_MS);
563+
#endif
514564
while (!usb_serial.connected()) {
515565
wait_ms(1);
516566
}
@@ -537,6 +587,10 @@ void test_serial_usb_reconnect()
537587

538588
greentea_send_kv(MSG_KEY_PORT_OPEN_WAIT, MSG_VALUE_DUMMY);
539589
// Wait for the host to open the port again.
590+
#if LINUX_HOST_DTR_FIX
591+
usb_serial.wait_ready();
592+
wait_ms(LINUX_HOST_DTR_FIX_DELAY_MS);
593+
#endif
540594
while (!usb_serial.connected()) {
541595
wait_ms(1);
542596
}
@@ -563,6 +617,10 @@ void test_serial_term_reopen()
563617
usb_serial.connect();
564618
greentea_send_kv(MSG_KEY_PORT_OPEN_CLOSE, MSG_VALUE_DUMMY);
565619
// Wait for the host to open the terminal.
620+
#if LINUX_HOST_DTR_FIX
621+
usb_serial.wait_ready();
622+
wait_ms(LINUX_HOST_DTR_FIX_DELAY_MS);
623+
#endif
566624
while (!usb_serial.connected()) {
567625
wait_ms(1);
568626
}
@@ -582,6 +640,10 @@ void test_serial_term_reopen()
582640

583641
greentea_send_kv(MSG_KEY_PORT_OPEN_CLOSE, MSG_VALUE_DUMMY);
584642
// Wait for the host to open the terminal again.
643+
#if LINUX_HOST_DTR_FIX
644+
usb_serial.wait_ready();
645+
wait_ms(LINUX_HOST_DTR_FIX_DELAY_MS);
646+
#endif
585647
while (!usb_serial.connected()) {
586648
wait_ms(1);
587649
}
@@ -613,9 +675,11 @@ void test_serial_getc()
613675
TestUSBSerial usb_serial(USB_SERIAL_VID, USB_SERIAL_PID, 1, usb_dev_sn);
614676
usb_serial.connect();
615677
greentea_send_kv(MSG_KEY_SEND_BYTES_SINGLE, MSG_VALUE_DUMMY);
616-
while (!usb_serial.connected()) {
617-
wait_ms(1);
618-
}
678+
#if LINUX_HOST_DTR_FIX
679+
usb_serial.wait_ready();
680+
wait_ms(LINUX_HOST_DTR_FIX_DELAY_MS);
681+
#endif
682+
usb_serial.wait_ready();
619683
for (int expected = 0xff; expected >= 0; expected--) {
620684
TEST_ASSERT_EQUAL_INT(expected, usb_serial.getc());
621685
}
@@ -643,6 +707,10 @@ void test_serial_printf_scanf()
643707
TestUSBSerial usb_serial(USB_SERIAL_VID, USB_SERIAL_PID, 1, usb_dev_sn);
644708
usb_serial.connect();
645709
greentea_send_kv(MSG_KEY_LOOPBACK, MSG_VALUE_DUMMY);
710+
#if LINUX_HOST_DTR_FIX
711+
usb_serial.wait_ready();
712+
wait_ms(LINUX_HOST_DTR_FIX_DELAY_MS);
713+
#endif
646714
usb_serial.wait_ready();
647715
static const char fmt[] = "Formatted\nstring %i.";
648716
int tx_val, rx_val, rc;
@@ -684,6 +752,10 @@ void test_serial_line_coding_change()
684752
TestUSBSerial usb_serial(USB_SERIAL_VID, USB_SERIAL_PID, 1, usb_dev_sn);
685753
usb_serial.connect();
686754
greentea_send_kv(MSG_KEY_CHANGE_LINE_CODING, MSG_VALUE_DUMMY);
755+
#if LINUX_HOST_DTR_FIX
756+
usb_serial.wait_ready();
757+
wait_ms(LINUX_HOST_DTR_FIX_DELAY_MS);
758+
#endif
687759
usb_serial.wait_ready();
688760
usb_serial.attach(line_coding_changed_cb);
689761
size_t num_line_codings = sizeof test_codings / sizeof test_codings[0];

0 commit comments

Comments
 (0)