Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
agausmann opened this issue Sep 1, 2023 · 1 comment · Fixed by #15473
Closed

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

agausmann opened this issue Sep 1, 2023 · 1 comment · Fixed by #15473

Comments

@agausmann
Copy link
Contributor

agausmann commented Sep 1, 2023

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'
@agausmann
Copy link
Contributor Author

I think this is a duplicate of #15384

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Untriaged
Status: Done
Development

Successfully merging a pull request may close this issue.

2 participants