[POLL (Open)] Blocking behaviour of Serial.USB during TX

Post here first, or if you can't find a relevant section!

Should SerialUSB.write() block when the host is slow to process data?

Poll ended at Tue Sep 19, 2017 4:37 pm

It should block indefinitely to guarantee delivery to the application.
1
6%
It should not block and return inmediately if there is no space in the buffer (return value indicates number of bytes queued for TX).
5
28%
It should block only for a set timeout period (return value indicates number of bytes queued for TX).
0
No votes
It should block only for a timeout period that matches the baud rate set on SerialUSB.Begin(bauds) (return value indicates number of bytes queue for TX).
4
22%
Configurable at runtime (blocking or non-blocking with small timeout)
7
39%
Other (please explain in a post)
1
6%
 
Total votes: 18

victor_pv
Posts: 1654
Joined: Mon Apr 27, 2015 12:12 pm

[POLL (Open)] Blocking behaviour of Serial.USB during TX

Post by victor_pv » Sun Aug 20, 2017 4:37 pm

There is a very long discussion about SerialUSB TX behavior in different cores, and the posibility of losing bytes.
There is mainly 2 different ways to manage USB transmissions if the host is not processing data at the rate the MCU is sending it:
On one hand SerialUSB.write () can just discard packets and not block after a set timeout period, returning a value that indicates how many bytes could be fit in the TX buffer. The timeout period can be hard set, or could be modified to match a certain baud rate, so timeout only if the host is acknowledging packets at a slower rate.
On the other hand the SerialUSB.write()can block indifinitely until data can be queued for TX, and return only if it was successfully queued.

Please vote below, and add any extra comment you want to add in the thread.

User avatar
martinayotte
Posts: 1222
Joined: Mon Apr 27, 2015 1:45 pm

Re: [POLL (Open)] Blocking behaviour of Serial.USB during TX

Post by martinayotte » Sun Aug 20, 2017 4:50 pm

I voted "other" simply because in the old libmaple F4, there is already a begining of solution I used since awhile :
https://github.com/rogerclarkmelbourne/ ... .h#L66-L67
May it could simply be extented by providing an additional timeout to enabledBlockingTx() ...
In other words, I would prefer an universal solution which cover all possible cases ! :ugeek:

stevestrong
Posts: 1611
Joined: Mon Oct 19, 2015 12:06 am
Location: Munich, Germany

Re: [POLL (Open)] Blocking behaviour of Serial.USB during TX

Post by stevestrong » Sun Aug 20, 2017 8:42 pm

I'm with Martin this time.
For applications where high Tx throughput is needed, it must be granted that the host is capable of that high speed.
Otherwise one should be able to select the desired behavior, blocking or not.

zmemw16
Posts: 1420
Joined: Wed Jul 08, 2015 2:09 pm
Location: St Annes, Lancs,UK

Re: [POLL (Open)] Blocking behaviour of Serial.USB during TX

Post by zmemw16 » Sun Aug 20, 2017 9:00 pm

+1

User avatar
RogerClark
Posts: 6917
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: [POLL (Open)] Blocking behaviour of Serial.USB during TX

Post by RogerClark » Sun Aug 20, 2017 9:21 pm

There is definitely a problem with blocking completely, because if you run you board from a USB charger or a battery and forget there is a serial.print in some bit of code.

The program hangs..

The same potentially applies if the terminal is not open.

I chose the second option, I.e don't block but return how much space is available, as it would allow the program to choose to block its self if necessary

However in hindsight, I should look to see what Serial.print returns in the rest of the Arduino world. Eg.on AVR and Due.

victor_pv
Posts: 1654
Joined: Mon Apr 27, 2015 12:12 pm

Re: [POLL (Open)] Blocking behaviour of Serial.USB during TX

Post by victor_pv » Mon Aug 21, 2017 12:57 am

Guys, since the option that was not included is the one apparently getting the most votes, I have added it as a separate option to track how much people goes for it.
Please vote again as the change cleared the voting.

But so far it seems the best option is to make it configurable.
I will look at teensy and due code to see what they do, and that could be default, and then configurable to act the opposite.

User avatar
RogerClark
Posts: 6917
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: [POLL (Open)] Blocking behaviour of Serial.USB during TX

Post by RogerClark » Mon Aug 21, 2017 1:27 am

Victor

I know I've mentioned this before, but ....

Can you also look at what happens in regard to DTR, beause AFIK our SerialUSB implementation does not currently behave the same way as the Due or the Teensy.
I think the difference is that we don't put any data into the USB TX buffer is DTR is not set, (Host terminal is not active), but the other boards still put stuff into the TX buffer

Currently people have issues with Libmaple not working correctly with some terminal's, who don't set DTR by default.
i.e Normal Arduino boards work with those terminals but LibMaple does not.

victor_pv
Posts: 1654
Joined: Mon Apr 27, 2015 12:12 pm

Re: [POLL (Open)] Blocking behaviour of Serial.USB during TX

Post by victor_pv » Mon Aug 21, 2017 2:46 am

This is what the DUE core does:
SerialUSB TX behavior
https://github.com/arduino/ArduinoCore- ... C.cpp#L264
/* only try to send bytes if the high-level CDC connection itself
is open (not just the pipe) - the OS should set lineState when the port
is opened and clear lineState when the port is closed.
bytes sent before the user opens the connection or after
the connection is closed are lost - just like with a UART. */
LineState contains 2 flags, DTR and RTS, besides baud rate and some other information.
The code checks if line rate != 0. In that case, it sends.
If lineState is 0, it doesn't even buffer the data, just returns 0, and sets a flag.
If lineState !=0, then tries to send data, and returns a value indicating what how much it sent. I need to dig more in the code to see if it can successfully send part of what's requested, but looks like it.

OK it seems like the low level driver will block until the ep is ready to take a packet. So the class is the one that will return 0 if the line is closed, but it the line is open, it blocks.
It doesn't seem to do any kind of buffering like we do for TX, it goes straight to the endpoint buffer, which for bulk transmission and USB FS is max 64 bytes.
There is no timeout or anything like that. If the line is open, it will block, if the line is closed, it returns right away. But line open is not just having a host connected to USB, but rather having an application open the port.
I'm not sure what would happen if the line is setup, application open the port, then cable is removed, and from the comments in the code, whoever wrote the library doesn't know either.
// TODO - ZE - check behavior on different OSes and test what happens if an
// open connection isn't broken cleanly (cable is yanked out, host dies
// or locks up, or host virtual serial port hangs)
Even if we manage to detect the line open and close correctly, we may want to be able to not block for too long.

EDIT:
The RX behavior:
It will not ACK RX packets until it's able to write them to the class buffer. So if the application is not reading, or not reading fast enough, it will block the host until there is space in the buffer. So on RX there shouldn't be any drop, which I think is the most appropriate.

User avatar
RogerClark
Posts: 6917
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: [POLL (Open)] Blocking behaviour of Serial.USB during TX

Post by RogerClark » Mon Aug 21, 2017 3:11 am

Thanks

victor_pv
Posts: 1654
Joined: Mon Apr 27, 2015 12:12 pm

Re: [POLL (Open)] Blocking behaviour of Serial.USB during TX

Post by victor_pv » Mon Aug 21, 2017 12:57 pm

Updated the previous post to add RX behavior in the DUE.

Post Reply