@@ -133,6 +133,14 @@ void EPBuffer<L>::init(uint8_t ep)
133
133
this ->reset ();
134
134
this ->rxWaiting = false ;
135
135
this ->txWaiting = false ;
136
+ this ->timedOut = false ;
137
+ this ->timeout = 100 ;
138
+ }
139
+
140
+ template <size_t L>
141
+ void EPBuffer<L>::setTimeout(uint16_t timeout)
142
+ {
143
+ this ->timeout = timeout;
136
144
}
137
145
138
146
template <size_t L>
@@ -236,6 +244,9 @@ void EPBuffer<L>::flush()
236
244
// fall through
237
245
case USBD_CONFIGURED:
238
246
case USBD_SUSPENDED: {
247
+ if (this ->timedOut ) {
248
+ break ;
249
+ }
239
250
// This will temporarily reenable and disable interrupts
240
251
auto canWrite = this ->waitForWriteComplete ();
241
252
if (canWrite) {
@@ -246,6 +257,7 @@ void EPBuffer<L>::flush()
246
257
// Only start the next transmission if the device hasn't been
247
258
// reset.
248
259
this ->txWaiting = true ;
260
+ this ->startTime = millis ();
249
261
usbd_ep_send (&USBCore ().usbDev (), this ->ep , (uint8_t *)this ->buf , this ->len ());
250
262
USBCore ().logEP (' >' , this ->ep , ' >' , this ->len ());
251
263
}
@@ -287,6 +299,7 @@ template<size_t L>
287
299
void EPBuffer<L>::transcIn()
288
300
{
289
301
this ->txWaiting = false ;
302
+ this ->timedOut = false ;
290
303
}
291
304
292
305
// Unused?
@@ -302,23 +315,117 @@ uint8_t* EPBuffer<L>::ptr()
302
315
template <size_t L>
303
316
bool EPBuffer<L>::waitForWriteComplete()
304
317
{
305
- // auto start = getCurrentMillis();
306
318
auto ok = true ;
319
+ auto desc = *EPBuffers ().desc (this ->ep );
320
+ auto udev = &USBCore ().usbDev ();
321
+
322
+ /*
323
+ * For interrupt EPs, count from now instead of from previous send.
324
+ * Otherwise, if a send occurs while the bus is suspended, the packet will
325
+ * be cheated of its full timeout.
326
+ */
327
+ if (desc.type () == USB_EP_ATTR_INT) {
328
+ this ->startTime = millis ();
329
+ }
307
330
do {
308
331
usb_enable_interrupts ();
309
- switch (USBCore (). usbDev (). cur_status ) {
332
+ switch (udev-> cur_status ) {
310
333
case USBD_DEFAULT:
311
334
case USBD_ADDRESSED:
312
335
ok = false ;
313
336
break ;
314
337
default :
315
338
break ;
316
339
}
317
- // if (getCurrentMillis() - start > 5) {
318
- // EPBuffers().buf(ep).transcIn();
319
- // ok = false;
320
- // }
321
340
usb_disable_interrupts ();
341
+ if (this ->txWaiting && millis () - this ->startTime > this ->timeout ) {
342
+ USBCore ().logEP (' X' , this ->ep , ' >' , this ->len ());
343
+ /*
344
+ * For interrupt EPs, overwrite the previous packet. In the common
345
+ * case of a key press HID report initiating a remote wakeup,
346
+ * transmission of the key release event might be delayed, because
347
+ * the host can't poll while the bus is suspended. If the
348
+ * application sends a key release event before the key press event
349
+ * is transmitted, that might time out. If the key release event is
350
+ * discarded due to the timeout, the host will never receive the
351
+ * key release event, leading to a stuck or repeating key.
352
+ */
353
+ if (desc.type () == USB_EP_ATTR_INT) {
354
+ /*
355
+ * Set the endpoint status to NAK, in an attempt to prevent
356
+ * the queued packet from being transmitted while being
357
+ * overwritten.
358
+ *
359
+ * This must be done in two steps. Unfortunately, the USBD
360
+ * peripheral's design doesn't seem to make it possible to
361
+ * atomically abort a queued transmission. Even if interrupts
362
+ * are disabled, the peripheral state machine continues to run.
363
+ *
364
+ * The endpoint status control bits are toggle-only (toggle on
365
+ * writing 1; unchanged on writing 0). If the TX state
366
+ * transitions from VALID to NAK during the read-modify-write,
367
+ * a toggle operation (XOR 0b01) intended to transition from
368
+ * VALID (0b11) to NAK (0b10) will set the status back to
369
+ * VALID. This will cause the previous packet to be sent again.
370
+ *
371
+ * Instead, set the status to DISABLED (0b00, via XOR 0b11),
372
+ * which will become STALL (0b01) if the peripheral transitions
373
+ * the status to NAK between the read and the write. This can
374
+ * happen if the transmission was in progress and the host ACKs
375
+ * exactly between the read and the write to update the status
376
+ * bits.
377
+ *
378
+ * Possible states after the first USBD_EP_TX_STAT_SET:
379
+ *
380
+ * - DISABLED (metastable if TX in progress)
381
+ * - STALL (stable; only possible if we lost the r-m-w race)
382
+ * - NAK (stable; only possible if TX completed after toggle)
383
+ *
384
+ * There is a small theoretical chance that the host will poll
385
+ * the endpoint again between the two updates to the status
386
+ * bits, which could lead to the host receiving a STALL
387
+ * handshake, which would put the data toggle bit out of sync.
388
+ *
389
+ * The second host poll cannot complete sooner than 34 bit times
390
+ * after the ACK from the first host poll. (2 bits inter-packet
391
+ * delay, 8 bits sync, 8 bits PID, 16 bits addr/endpoint/CRC,
392
+ * about 2.83 microseconds) The second status bit update will
393
+ * complete before then, assuming reasonable CPU clock speeds
394
+ * and no lengthy interrupt handler executions occurring.
395
+ *
396
+ * On the other hand, it's unknown when exactly the peripheral
397
+ * checks the endpoint status bits to decide which response to
398
+ * send to an IN poll. It might latch them at EOP, or SOP, or
399
+ * maybe PID, or it might wait until after checking the CRC. So
400
+ * the actual available time might be between 0 and 34 bit
401
+ * times.
402
+ *
403
+ * We could globally disable interrupts to mitigate that, if
404
+ * necessary.
405
+ */
406
+ USBD_EP_TX_STAT_SET (this ->ep , EPTX_DISABLED);
407
+ if (USBD_EPxCS (this ->ep ) & EPxCS_TX_STA == EPTX_DISABLED) {
408
+ /*
409
+ * If the endpoint is disabled, there might still be a
410
+ * transmission in progress. Wait for it to complete:
411
+ *
412
+ * 1 byte sync + 1 byte PID + 64 bytes data + 2 bytes CRC,
413
+ * 1 turn-around time,
414
+ * 1 byte sync + 1 byte PID (handshake)
415
+ * assuming maximum bit stuffing at full speed (12MHz).
416
+ */
417
+ delayMicroseconds (56 );
418
+ }
419
+ // In case TX was in progress and completed
420
+ USBD_EP_TX_ST_CLEAR (this ->ep );
421
+ USBD_EP_TX_STAT_SET (this ->ep , EPTX_NAK);
422
+ break ;
423
+ } else {
424
+ ok = false ;
425
+ this ->timedOut = true ;
426
+ break ;
427
+ }
428
+ }
322
429
} while (ok && this ->txWaiting );
323
430
return ok;
324
431
}
@@ -878,6 +985,11 @@ int USBCore_::flush(uint8_t ep)
878
985
return 0 ;
879
986
}
880
987
988
+ void USBCore_::setTimeout (uint8_t ep, uint16_t timeout)
989
+ {
990
+ EPBuffers ().buf (ep).setTimeout (timeout);
991
+ }
992
+
881
993
void USBCore_::transcSetupHelper (usb_dev* usbd, uint8_t ep)
882
994
{
883
995
USBCore_* core = (USBCore_*)usbd->user_data ;
0 commit comments