Skip to content

Commit 9007ef2

Browse files
committed
pbio/drv/usb_stm32: Don't stall when no app connected.
1 parent dfbcfa8 commit 9007ef2

File tree

1 file changed

+54
-8
lines changed

1 file changed

+54
-8
lines changed

lib/pbio/drv/usb/usb_stm32.c

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <usbd_desc.h>
1818
#include <usbd_pybricks.h>
1919

20+
#include <pbdrv/clock.h>
2021
#include <pbdrv/usb.h>
2122
#include <pbio/protocol.h>
2223
#include <pbio/util.h>
@@ -39,13 +40,58 @@ static volatile uint32_t usb_response_sz;
3940
static volatile uint32_t usb_status_sz;
4041
static volatile uint32_t usb_stdout_sz;
4142
static volatile bool transmitting;
43+
static volatile uint32_t transmission_start_time;
4244

4345
static USBD_HandleTypeDef husbd;
4446
static PCD_HandleTypeDef hpcd;
4547

4648
static volatile bool vbus_active;
4749
static pbdrv_usb_bcd_t pbdrv_usb_bcd;
4850

51+
/**
52+
* Set the USB transmit state.
53+
*
54+
* @param [in] active True indicates that USB is currently transmitting data,
55+
* otherwise false.
56+
*/
57+
static void pbdrv_usb_stm32_tx_active_set(bool active) {
58+
if (active) {
59+
transmitting = true;
60+
transmission_start_time = pbdrv_clock_get_ms();
61+
} else {
62+
transmitting = false;
63+
}
64+
}
65+
66+
/**
67+
* Checks if the USB interface can be used for stdout.
68+
*
69+
* Essentially tests for being connected and not being stalled. Can be used by
70+
* applications to test if it should wait or skip waiting on transmission.
71+
*
72+
* This relies on the status message that is periodically sent to the host but
73+
* stalls if not read by the host application.
74+
*
75+
* REVISIT: It would be better to update the protocol to expect periodic status
76+
* messages from the host rather than making it implicit.
77+
*
78+
* @return true if the USB interface is ready to send stdout data, otherwise false.
79+
*/
80+
static bool pbdrv_usb_stdout_is_awaitable(void) {
81+
// Not physically connected to a host.
82+
if (pbdrv_usb_get_bcd() == PBDRV_USB_BCD_NONE) {
83+
return false;
84+
}
85+
86+
if (!transmitting) {
87+
// Ready to send, so can send stdout data in principle.
88+
return true;
89+
}
90+
91+
// Currently transmitting data. Don't await if stalled.
92+
return pbdrv_clock_get_ms() - transmission_start_time < 600;
93+
}
94+
4995
/**
5096
* Battery charger detection task.
5197
*
@@ -160,9 +206,9 @@ pbio_error_t pbdrv_usb_stdout_tx(const uint8_t *data, uint32_t *size) {
160206
uint32_t ptr_len = sizeof(usb_stdout_buf);
161207
uint32_t full_size = *size;
162208

163-
// TODO: return PBIO_ERROR_INVALID_OP if app flag is not set. Also need a
164-
// timeout in case the app crashes and doesn't clear the flag on exit.
165-
209+
if (!pbdrv_usb_stdout_is_awaitable()) {
210+
return PBIO_ERROR_INVALID_OP;
211+
}
166212
if (usb_stdout_sz) {
167213
*size = 0;
168214
return PBIO_ERROR_AGAIN;
@@ -204,7 +250,7 @@ static USBD_StatusTypeDef Pybricks_Itf_Init(void) {
204250
usb_response_sz = 0;
205251
usb_status_sz = 0;
206252
usb_stdout_sz = 0;
207-
transmitting = false;
253+
pbdrv_usb_stm32_tx_active_set(false);
208254

209255
return USBD_OK;
210256
}
@@ -259,7 +305,7 @@ static USBD_StatusTypeDef Pybricks_Itf_TransmitCplt(uint8_t *Buf, uint32_t Len,
259305
ret = USBD_FAIL;
260306
}
261307

262-
transmitting = false;
308+
pbdrv_usb_stm32_tx_active_set(false);
263309
process_poll(&pbdrv_usb_process);
264310
return ret;
265311
}
@@ -383,7 +429,7 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
383429

384430
// Transmit. Give priority to response, then status updates, then stdout.
385431
if (usb_response_sz) {
386-
transmitting = true;
432+
pbdrv_usb_stm32_tx_active_set(true);
387433
USBD_Pybricks_TransmitPacket(&husbd, usb_response_buf, usb_response_sz);
388434
} else if ((new_status_flags != prev_status_flags) || etimer_expired(&timer)) {
389435
usb_status_buf[0] = USBD_PYBRICKS_IN_EP_MSG_EVENT;
@@ -394,10 +440,10 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
394440
etimer_restart(&timer);
395441
prev_status_flags = new_status_flags;
396442

397-
transmitting = true;
443+
pbdrv_usb_stm32_tx_active_set(true);
398444
USBD_Pybricks_TransmitPacket(&husbd, usb_status_buf, usb_status_sz);
399445
} else if (usb_stdout_sz) {
400-
transmitting = true;
446+
pbdrv_usb_stm32_tx_active_set(true);
401447
USBD_Pybricks_TransmitPacket(&husbd, usb_stdout_buf, usb_stdout_sz);
402448
}
403449
}

0 commit comments

Comments
 (0)