Skip to content

Commit cba2c19

Browse files
nkarstensdlech
authored andcommitted
pbdrv/usb: Add support for transmitting stdout over USB.
Add partial support for transmitting stdout messages over USB. TODO: Need to add implementation of subscribing to have this not enabled all of the time. Then this can be integrated with the mphal in MicroPython. Signed-off-by: Nate Karstens <[email protected]>
1 parent c70fa81 commit cba2c19

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

lib/pbio/drv/usb/usb_stm32.c

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@ PROCESS(pbdrv_usb_process, "USB");
3232
static uint8_t usb_in_buf[USBD_PYBRICKS_MAX_PACKET_SIZE] __aligned(4);
3333
static uint8_t usb_response_buf[1 + sizeof(uint32_t)] __aligned(4);
3434
static 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);
3536
static volatile uint32_t usb_in_sz;
3637
static volatile uint32_t usb_response_sz;
3738
static volatile uint32_t usb_status_sz;
39+
static volatile uint32_t usb_stdout_sz;
3840
static volatile bool transmitting;
3941

4042
static 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

lib/pbio/include/pbdrv/usb.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
#ifndef _PBDRV_USB_H_
1010
#define _PBDRV_USB_H_
1111

12+
#include <stdbool.h>
13+
1214
#include <pbdrv/config.h>
15+
#include <pbio/error.h>
1316

1417
/**
1518
* Indicates battery charging capabilites that were detected on a USB port.
@@ -37,12 +40,32 @@ typedef enum {
3740
*/
3841
pbdrv_usb_bcd_t pbdrv_usb_get_bcd(void);
3942

43+
/**
44+
* Transmits the given buffer over the USB stdout stream.
45+
* @return The result of the operation.
46+
*/
47+
pbio_error_t pbdrv_usb_stdout_tx(const uint8_t *data, uint32_t *size);
48+
49+
/**
50+
* Indicates if the USB stdout stream is idle.
51+
* @return true if the USB stdout stream is idle.
52+
*/
53+
bool pbdrv_usb_stdout_tx_is_idle(void);
54+
4055
#else // PBDRV_CONFIG_USB
4156

4257
static inline pbdrv_usb_bcd_t pbdrv_usb_get_bcd(void) {
4358
return PBDRV_USB_BCD_NONE;
4459
}
4560

61+
static inline pbio_error_t pbdrv_usb_stdout_tx(const uint8_t *data, uint32_t *size) {
62+
return PBIO_SUCCESS;
63+
}
64+
65+
static inline bool pbdrv_usb_stdout_tx_is_idle(void) {
66+
return true;
67+
}
68+
4669
#endif // PBDRV_CONFIG_USB
4770

4871
#endif // _PBDRV_USB_H_

0 commit comments

Comments
 (0)