Skip to content

Host receiving data from USBSerial will timeout if data size is 64 #15451

Closed
@agausmann

Description

@agausmann

Description of defect

When using USBSerial::send with an application running on a Windows host, if the send length is divisible by 64 bytes, then Windows will not send the data to the application until the device sends additional data that is not divisible by 64 bytes. If nothing else is sent after the affected packet (i.e. it is the end of the transmission), then the read on the host will eventually time out.

(Tested on Windows 10 and Linux 6.4, only Windows exhibited this problem)

Target(s) affected by this defect ?

  • NUCLEO_H743ZI2
  • Probably others, it seems like a platform issue

Toolchain(s) (name and version) displaying this defect ?

  • arm-none-eabi-gcc (GNU Arm Embedded Toolchain 10.3-2021.10) 10.3.1 20210824 (release)

What version of Mbed-os are you using (tag or sha) ?

What version(s) of tools are you using. List all that apply (E.g. mbed-cli)

  • mbed-tools 7.59.0

How is this defect reproduced ?

https://github.com/agausmann/mbed-os-usbserial-hang

main.cpp:

#include "mbed.h"

#include <usb/USBSerial.h>

// Any X divisible by 64 will time out reads by a Windows host
#define X 64

int main()
{
    USBSerial serial;

    uint8_t buf[X];
    memset(buf, 'A', X);
    buf[X - 1] = '\n';

    while (1) {
        // Wait until prompted by host
        while (!serial.receive(buf, 1)) {}

        serial.send(buf, X);

        // Sending data not divisible by 64 will fix the timeout on the host.
        // buf[0] = 'B';
        // serial.send(buf, 1);
    }
    return 0;
}

host.py:

# pip install pyserial
import serial
from serial.tools import list_ports
import time

# USB VID:PID 1f00:2012
ports = list(list_ports.grep('1f00:2012'))
print(ports)

conn = serial.Serial(ports[0].device)
conn.timeout = 1
i = 0
while True:
    conn.write(b'a')

    # "Read until an expected sequence is found  ... or until timeout occurs.
    # If a timeout is set it may return fewer characters than requested"
    buf = conn.read_until(b'\n')

    if not buf.endswith(b'\n'):
        print('TIMEOUT')
        
    print(i, buf)
    i += 1
    time.sleep(0.1)
  • Compile the code, e.g. mbed-tools compile -m NUCLEO_H743ZI2 -t GCC_ARM
  • Flash the device
  • Run host.py (on a Windows host!) with the device USB connected.

If X is 64 or any other number divisible by 64, then as stated, it will cause timeouts in the host program:

TIMEOUT
0 b''
TIMEOUT
1 b''
TIMEOUT
2 b''
TIMEOUT
3 b''

If X is not divisible by 64 (e.g. 63), then data will be promptly received by the host program:

0 b'aAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
1 b'aAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
2 b'aAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
3 b'aAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
4 b'aAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
5 b'aAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
6 b'aAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'

If X is divisible by 64, but another data packet is sent afterward that is not divisible by 64 (by uncommenting the second call to serial.send), then the data will still be received promptly. (and the data sent after the newline will be left in queue for the beginning of the next line):

0 b'aAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
1 b'BaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
2 b'BaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
3 b'BaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
4 b'BaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
5 b'BaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
6 b'BaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
7 b'BaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'
8 b'BaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n'

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Done

    Status

    Untriaged

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions