@@ -32,9 +32,11 @@ PROCESS(pbdrv_usb_process, "USB");
3232static uint8_t usb_in_buf [USBD_PYBRICKS_MAX_PACKET_SIZE ] __aligned (4 );
3333static uint8_t usb_response_buf [1 + sizeof (uint32_t )] __aligned (4 );
3434static uint8_t usb_status_buf [1 + PBSYS_STATUS_REPORT_SIZE ] __aligned (4 );
35+ static uint8_t usb_stdout_buf [USBD_PYBRICKS_MAX_PACKET_SIZE ] __aligned (4 );
3536static volatile uint32_t usb_in_sz ;
3637static volatile uint32_t usb_response_sz ;
3738static volatile uint32_t usb_status_sz ;
39+ static volatile uint32_t usb_stdout_sz ;
3840static volatile bool transmitting ;
3941
4042static USBD_HandleTypeDef husbd ;
@@ -137,6 +139,52 @@ void pbdrv_usb_stm32_handle_vbus_irq(bool active) {
137139 process_poll (& pbdrv_usb_process );
138140}
139141
142+ /**
143+ * Queues data to be transmitted via USB.
144+ * @param data [in] The data to be sent.
145+ * @param size [in, out] The size of @p data in bytes. After return, @p size
146+ * contains the number of bytes actually written.
147+ * @return ::PBIO_SUCCESS if @p data was queued, ::PBIO_ERROR_AGAIN
148+ * if @p data could not be queued at this time (e.g. buffer
149+ * is full), ::PBIO_ERROR_INVALID_OP if there is not an
150+ * active USB connection or ::PBIO_ERROR_NOT_SUPPORTED
151+ * if this platform does not support USB.
152+ */
153+ pbio_error_t pbdrv_usb_stdout_tx (const uint8_t * data , uint32_t * size ) {
154+ uint8_t * ptr = usb_stdout_buf ;
155+ uint32_t ptr_len = sizeof (usb_stdout_buf );
156+
157+ // TODO: return PBIO_ERROR_INVALID_OP if app flag is not set. Also need a
158+ // timeout in case the app crashes and doesn't clear the flag on exit.
159+
160+ if (usb_stdout_sz ) {
161+ return PBIO_ERROR_AGAIN ;
162+ }
163+
164+ * ptr ++ = USBD_PYBRICKS_IN_EP_MSG_EVENT ;
165+ ptr_len -- ;
166+
167+ * ptr ++ = PBIO_PYBRICKS_EVENT_WRITE_STDOUT ;
168+ ptr_len -- ;
169+
170+ * size = MIN (* size , ptr_len );
171+ memcpy (ptr , data , * size );
172+
173+ usb_stdout_sz = 1 + 1 + * size ;
174+
175+ process_poll (& pbdrv_usb_process );
176+
177+ return PBIO_SUCCESS ;
178+ }
179+
180+ /**
181+ * Indicates if there is stdout data waiting to be transmitted over USB.
182+ * @retval false if stdout data is currently being transmitted.
183+ */
184+ bool pbdrv_usb_stdout_tx_is_idle (void ) {
185+ return usb_stdout_sz == 0 ;
186+ }
187+
140188/**
141189 * @brief Pybricks_Itf_Init
142190 * Initializes the Pybricks media low layer
@@ -148,6 +196,7 @@ static USBD_StatusTypeDef Pybricks_Itf_Init(void) {
148196 usb_in_sz = 0 ;
149197 usb_response_sz = 0 ;
150198 usb_status_sz = 0 ;
199+ usb_stdout_sz = 0 ;
151200 transmitting = false;
152201
153202 return USBD_OK ;
@@ -197,6 +246,8 @@ static USBD_StatusTypeDef Pybricks_Itf_TransmitCplt(uint8_t *Buf, uint32_t Len,
197246 usb_response_sz = 0 ;
198247 } else if (Buf == usb_status_buf ) {
199248 usb_status_sz = 0 ;
249+ } else if (Buf == usb_stdout_buf ) {
250+ usb_stdout_sz = 0 ;
200251 } else {
201252 ret = USBD_FAIL ;
202253 }
@@ -314,7 +365,7 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
314365
315366 new_status_flags = pbsys_status_get_flags ();
316367
317- // Transmit. Give priority to response, then status updates.
368+ // Transmit. Give priority to response, then status updates, then stdout .
318369 if (usb_response_sz ) {
319370 transmitting = true;
320371 USBD_Pybricks_TransmitPacket (& husbd , usb_response_buf , usb_response_sz );
@@ -329,6 +380,9 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
329380
330381 transmitting = true;
331382 USBD_Pybricks_TransmitPacket (& husbd , usb_status_buf , usb_status_sz );
383+ } else if (usb_stdout_sz ) {
384+ transmitting = true;
385+ USBD_Pybricks_TransmitPacket (& husbd , usb_stdout_buf , usb_stdout_sz );
332386 }
333387 }
334388
0 commit comments