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>
@@ -31,9 +32,13 @@ PROCESS(pbdrv_usb_process, "USB");
3132static uint8_t usb_in_buf [USBD_PYBRICKS_MAX_PACKET_SIZE ];
3233static uint8_t usb_response_buf [1 + sizeof (uint32_t )];
3334static uint8_t usb_status_buf [1 + 1 + sizeof (uint32_t )];
35+ static uint8_t usb_stdout_buf [USBD_PYBRICKS_MAX_PACKET_SIZE ];
3436static volatile uint32_t usb_in_sz ;
3537static volatile uint32_t usb_response_sz ;
3638static volatile uint32_t usb_status_sz ;
39+ static volatile uint32_t usb_stdout_sz ;
40+ static volatile clock_time_t usb_response_tx_time ;
41+ static volatile clock_time_t usb_stdout_tx_time ;
3742static volatile bool transmitting ;
3843
3944static USBD_HandleTypeDef husbd ;
@@ -136,6 +141,53 @@ void pbdrv_usb_stm32_handle_vbus_irq(bool active) {
136141 process_poll (& pbdrv_usb_process );
137142}
138143
144+ /**
145+ * Queues data to be transmitted via USB.
146+ * @param data [in] The data to be sent.
147+ * @param size [in, out] The size of @p data in bytes. After return, @p size
148+ * contains the number of bytes actually written.
149+ * @return ::PBIO_SUCCESS if @p data was queued, ::PBIO_ERROR_AGAIN
150+ * if @p data could not be queued at this time (e.g. buffer
151+ * is full), ::PBIO_ERROR_INVALID_OP if there is not an
152+ * active USB connection or ::PBIO_ERROR_NOT_SUPPORTED
153+ * if this platform does not support USB.
154+ */
155+ pbio_error_t pbdrv_usb_stdout_tx (const uint8_t * data , uint32_t * size ) {
156+ uint8_t * ptr = usb_stdout_buf ;
157+ uint32_t ptr_len = sizeof (usb_stdout_buf );
158+
159+ // TODO: return PBIO_ERROR_INVALID_OP if not connected
160+
161+ if (usb_stdout_sz ) {
162+ return PBIO_ERROR_AGAIN ;
163+ }
164+
165+ * ptr = USBD_PYBRICKS_MSG_EVENT ;
166+ ptr ++ ;
167+ ptr_len -- ;
168+
169+ * ptr = PBIO_PYBRICKS_EVENT_WRITE_STDOUT ;
170+ ptr ++ ;
171+ ptr_len -- ;
172+
173+ * size = MIN (* size , ptr_len );
174+ memcpy (ptr , data , * size );
175+
176+ usb_stdout_sz = 1 + 1 + * size ;
177+
178+ process_poll (& pbdrv_usb_process );
179+
180+ return PBIO_SUCCESS ;
181+ }
182+
183+ /**
184+ * Indicates if there is stdout data waiting to be transmitted over USB.
185+ * @retval false if stdout data is currently being transmitted.
186+ */
187+ bool pbdrv_usb_stdout_tx_is_idle (void ) {
188+ return usb_stdout_sz == 0 ;
189+ }
190+
139191/**
140192 * @brief Pybricks_Itf_Init
141193 * Initializes the Pybricks media low layer
@@ -147,6 +199,7 @@ static USBD_StatusTypeDef Pybricks_Itf_Init(void) {
147199 usb_in_sz = 0 ;
148200 usb_response_sz = 0 ;
149201 usb_status_sz = 0 ;
202+ usb_stdout_sz = 0 ;
150203 transmitting = false;
151204
152205 return USBD_OK ;
@@ -200,6 +253,8 @@ static USBD_StatusTypeDef Pybricks_Itf_TransmitCplt(uint8_t *Buf, uint32_t *Len,
200253 usb_response_sz = 0 ;
201254 } else if (Buf == usb_status_buf ) {
202255 usb_status_sz = 0 ;
256+ } else if (Buf == usb_stdout_buf ) {
257+ usb_stdout_sz = 0 ;
203258 } else {
204259 ret = USBD_FAIL ;
205260 }
@@ -322,7 +377,8 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
322377
323378 new_status_flags = pbsys_status_get_flags ();
324379
325- // Transmit. Give priority to status updates.
380+ // Transmit. Give priority to status updates, then
381+ // cycle between response and stdout buffers.
326382 if ((new_status_flags != prev_status_flags ) || etimer_expired (& timer )) {
327383
328384 usb_status_buf [0 ] = USBD_PYBRICKS_MSG_EVENT ;
@@ -334,10 +390,18 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
334390 transmitting = true;
335391 USBD_Pybricks_TransmitPacket (& husbd , usb_status_buf , usb_status_sz );
336392
337- } else if (usb_response_sz ) {
393+ } else if (usb_response_sz &&
394+ (!usb_stdout_sz || (usb_response_tx_time < usb_stdout_tx_time ))) {
338395
339396 transmitting = true;
397+ usb_response_tx_time = clock_time ();
340398 USBD_Pybricks_TransmitPacket (& husbd , usb_response_buf , usb_response_sz );
399+
400+ } else if (usb_stdout_sz ) {
401+
402+ transmitting = true;
403+ usb_stdout_tx_time = clock_time ();
404+ USBD_Pybricks_TransmitPacket (& husbd , usb_stdout_buf , usb_stdout_sz );
341405 }
342406 }
343407
0 commit comments