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;
3940static volatile uint32_t usb_status_sz ;
4041static volatile uint32_t usb_stdout_sz ;
4142static volatile bool transmitting ;
43+ static volatile uint32_t transmission_start_time ;
4244
4345static USBD_HandleTypeDef husbd ;
4446static PCD_HandleTypeDef hpcd ;
4547
4648static volatile bool vbus_active ;
4749static 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