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 *
@@ -155,9 +201,9 @@ pbio_error_t pbdrv_usb_stdout_tx(const uint8_t *data, uint32_t *size) {
155201 uint8_t * ptr = usb_stdout_buf ;
156202 uint32_t ptr_len = sizeof (usb_stdout_buf );
157203
158- // TODO: return PBIO_ERROR_INVALID_OP if app flag is not set. Also need a
159- // timeout in case the app crashes and doesn't clear the flag on exit.
160-
204+ if (! pbdrv_usb_stdout_is_awaitable ()) {
205+ return PBIO_ERROR_INVALID_OP ;
206+ }
161207 if (usb_stdout_sz ) {
162208 return PBIO_ERROR_AGAIN ;
163209 }
@@ -198,7 +244,7 @@ static USBD_StatusTypeDef Pybricks_Itf_Init(void) {
198244 usb_response_sz = 0 ;
199245 usb_status_sz = 0 ;
200246 usb_stdout_sz = 0 ;
201- transmitting = false;
247+ pbdrv_usb_stm32_tx_active_set ( false) ;
202248
203249 return USBD_OK ;
204250}
@@ -253,7 +299,7 @@ static USBD_StatusTypeDef Pybricks_Itf_TransmitCplt(uint8_t *Buf, uint32_t Len,
253299 ret = USBD_FAIL ;
254300 }
255301
256- transmitting = false;
302+ pbdrv_usb_stm32_tx_active_set ( false) ;
257303 process_poll (& pbdrv_usb_process );
258304 return ret ;
259305}
@@ -368,7 +414,7 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
368414
369415 // Transmit. Give priority to response, then status updates, then stdout.
370416 if (usb_response_sz ) {
371- transmitting = true;
417+ pbdrv_usb_stm32_tx_active_set ( true) ;
372418 USBD_Pybricks_TransmitPacket (& husbd , usb_response_buf , usb_response_sz );
373419 } else if ((new_status_flags != prev_status_flags ) || etimer_expired (& timer )) {
374420 usb_status_buf [0 ] = USBD_PYBRICKS_IN_EP_MSG_EVENT ;
@@ -379,10 +425,10 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
379425 etimer_restart (& timer );
380426 prev_status_flags = new_status_flags ;
381427
382- transmitting = true;
428+ pbdrv_usb_stm32_tx_active_set ( true) ;
383429 USBD_Pybricks_TransmitPacket (& husbd , usb_status_buf , usb_status_sz );
384430 } else if (usb_stdout_sz ) {
385- transmitting = true;
431+ pbdrv_usb_stm32_tx_active_set ( true) ;
386432 USBD_Pybricks_TransmitPacket (& husbd , usb_stdout_buf , usb_stdout_sz );
387433 }
388434 }
0 commit comments