Skip to content

Commit 13b371b

Browse files
committed
Merge remote-tracking branch 'sandeep/usb-send-timeout-take-2' into HEAD
2 parents f69e17e + b2462a5 commit 13b371b

File tree

2 files changed

+42
-24
lines changed

2 files changed

+42
-24
lines changed

cores/arduino/USB/CDC.cpp

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -205,28 +205,14 @@ void Serial_::flush(void)
205205

206206
size_t Serial_::write(const uint8_t *buffer, size_t size)
207207
{
208-
/* only try to send bytes if the high-level CDC connection itself
209-
is open (not just the pipe) - the OS should set lineState when the port
210-
is opened and clear lineState when the port is closed.
211-
bytes sent before the user opens the connection or after
212-
the connection is closed are lost - just like with a UART. */
213-
214-
// TODO - ZE - check behavior on different OSes and test what happens if an
215-
// open connection isn't broken cleanly (cable is yanked out, host dies
216-
// or locks up, or host virtual serial port hangs)
217-
if (_usbLineInfo.lineState > 0) // Problem with Windows(R)
218-
{
219-
uint32_t r = usb.send(CDC_ENDPOINT_IN, buffer, size);
208+
uint32_t r = usb.send(CDC_ENDPOINT_IN, buffer, size);
220209

221-
if (r > 0) {
222-
return r;
223-
} else {
224-
setWriteError();
225-
return 0;
226-
}
210+
if (r > 0) {
211+
return r;
212+
} else {
213+
setWriteError();
214+
return 0;
227215
}
228-
setWriteError();
229-
return 0;
230216
}
231217

232218
size_t Serial_::write(uint8_t c) {

cores/arduino/USB/USBCore.cpp

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,19 @@ uint8_t USBDeviceClass::armRecv(uint32_t ep)
598598
return usbd.epBank0ByteCount(ep);
599599
}
600600

601+
// Timeout for sends
602+
#define TX_TIMEOUT_MS 70
603+
604+
static char LastTransmitTimedOut[7] = {
605+
0,
606+
0,
607+
0,
608+
0,
609+
0,
610+
0,
611+
0
612+
};
613+
601614
// Blocking Send of data to an endpoint
602615
uint32_t USBDeviceClass::send(uint32_t ep, const void *data, uint32_t len)
603616
{
@@ -619,6 +632,29 @@ uint32_t USBDeviceClass::send(uint32_t ep, const void *data, uint32_t len)
619632
// Flash area
620633
while (len != 0)
621634
{
635+
if (usbd.epBank1IsReady(ep)) {
636+
// previous transfer is still not complete
637+
638+
// convert the timeout from microseconds to a number of times through
639+
// the wait loop; it takes (roughly) 23 clock cycles per iteration.
640+
uint32_t timeout = microsecondsToClockCycles(TX_TIMEOUT_MS * 1000) / 23;
641+
642+
// Wait for (previous) transfer to complete
643+
// inspired by Paul Stoffregen's work on Teensy
644+
while (!usbd.epBank1IsTransferComplete(ep)) {
645+
if (LastTransmitTimedOut[ep] || timeout-- == 0) {
646+
LastTransmitTimedOut[ep] = 1;
647+
648+
// set byte count to zero, so that ZLP is sent
649+
// instead of stale data
650+
usbd.epBank1SetByteCount(ep, 0);
651+
return -1;
652+
}
653+
}
654+
}
655+
656+
LastTransmitTimedOut[ep] = 0;
657+
622658
if (len >= EPX_SIZE) {
623659
length = EPX_SIZE - 1;
624660
} else {
@@ -637,10 +673,6 @@ uint32_t USBDeviceClass::send(uint32_t ep, const void *data, uint32_t len)
637673
// RAM buffer is full, we can send data (IN)
638674
usbd.epBank1SetReady(ep);
639675

640-
// Wait for transfer to complete
641-
while (!usbd.epBank1IsTransferComplete(ep)) {
642-
; // need fire exit.
643-
}
644676
written += length;
645677
len -= length;
646678
data = (char *)data + length;

0 commit comments

Comments
 (0)