77
88#if PBDRV_CONFIG_USB_STM32F4
99
10+ #include <string.h>
1011#include <stdbool.h>
1112
1213#include <contiki.h>
@@ -32,9 +33,11 @@ PROCESS(pbdrv_usb_process, "USB");
3233static uint8_t usb_in_buf [USBD_PYBRICKS_MAX_PACKET_SIZE ] __aligned (4 );
3334static uint8_t usb_response_buf [1 + sizeof (uint32_t )] __aligned (4 );
3435static uint8_t usb_status_buf [1 + PBSYS_STATUS_REPORT_SIZE ] __aligned (4 );
36+ static uint8_t usb_stdout_buf [USBD_PYBRICKS_MAX_PACKET_SIZE ] __aligned (4 );
3537static volatile uint32_t usb_in_sz ;
3638static volatile uint32_t usb_response_sz ;
3739static volatile uint32_t usb_status_sz ;
40+ static volatile uint32_t usb_stdout_sz ;
3841static volatile bool transmitting ;
3942
4043static USBD_HandleTypeDef husbd ;
@@ -137,6 +140,52 @@ void pbdrv_usb_stm32_handle_vbus_irq(bool active) {
137140 process_poll (& pbdrv_usb_process );
138141}
139142
143+ /**
144+ * Queues data to be transmitted via USB.
145+ * @param data [in] The data to be sent.
146+ * @param size [in, out] The size of @p data in bytes. After return, @p size
147+ * contains the number of bytes actually written.
148+ * @return ::PBIO_SUCCESS if @p data was queued, ::PBIO_ERROR_AGAIN
149+ * if @p data could not be queued at this time (e.g. buffer
150+ * is full), ::PBIO_ERROR_INVALID_OP if there is not an
151+ * active USB connection or ::PBIO_ERROR_NOT_SUPPORTED
152+ * if this platform does not support USB.
153+ */
154+ pbio_error_t pbdrv_usb_stdout_tx (const uint8_t * data , uint32_t * size ) {
155+ uint8_t * ptr = usb_stdout_buf ;
156+ uint32_t ptr_len = sizeof (usb_stdout_buf );
157+
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+
161+ if (usb_stdout_sz ) {
162+ return PBIO_ERROR_AGAIN ;
163+ }
164+
165+ * ptr ++ = USBD_PYBRICKS_IN_EP_MSG_EVENT ;
166+ ptr_len -- ;
167+
168+ * ptr ++ = PBIO_PYBRICKS_EVENT_WRITE_STDOUT ;
169+ ptr_len -- ;
170+
171+ * size = MIN (* size , ptr_len );
172+ memcpy (ptr , data , * size );
173+
174+ usb_stdout_sz = 1 + 1 + * size ;
175+
176+ process_poll (& pbdrv_usb_process );
177+
178+ return PBIO_SUCCESS ;
179+ }
180+
181+ /**
182+ * Indicates if there is stdout data waiting to be transmitted over USB.
183+ * @retval false if stdout data is currently being transmitted.
184+ */
185+ bool pbdrv_usb_stdout_tx_is_idle (void ) {
186+ return usb_stdout_sz == 0 ;
187+ }
188+
140189/**
141190 * @brief Pybricks_Itf_Init
142191 * Initializes the Pybricks media low layer
@@ -148,6 +197,7 @@ static USBD_StatusTypeDef Pybricks_Itf_Init(void) {
148197 usb_in_sz = 0 ;
149198 usb_response_sz = 0 ;
150199 usb_status_sz = 0 ;
200+ usb_stdout_sz = 0 ;
151201 transmitting = false;
152202
153203 return USBD_OK ;
@@ -197,6 +247,8 @@ static USBD_StatusTypeDef Pybricks_Itf_TransmitCplt(uint8_t *Buf, uint32_t Len,
197247 usb_response_sz = 0 ;
198248 } else if (Buf == usb_status_buf ) {
199249 usb_status_sz = 0 ;
250+ } else if (Buf == usb_stdout_buf ) {
251+ usb_stdout_sz = 0 ;
200252 } else {
201253 ret = USBD_FAIL ;
202254 }
@@ -314,7 +366,7 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
314366
315367 new_status_flags = pbsys_status_get_flags ();
316368
317- // Transmit. Give priority to response, then status updates.
369+ // Transmit. Give priority to response, then status updates, then stdout .
318370 if (usb_response_sz ) {
319371 transmitting = true;
320372 USBD_Pybricks_TransmitPacket (& husbd , usb_response_buf , usb_response_sz );
@@ -329,6 +381,9 @@ PROCESS_THREAD(pbdrv_usb_process, ev, data) {
329381
330382 transmitting = true;
331383 USBD_Pybricks_TransmitPacket (& husbd , usb_status_buf , usb_status_sz );
384+ } else if (usb_stdout_sz ) {
385+ transmitting = true;
386+ USBD_Pybricks_TransmitPacket (& husbd , usb_stdout_buf , usb_stdout_sz );
332387 }
333388 }
334389
0 commit comments