8000 rp2: fix usb endpoint handling by hoihu · Pull Request #8040 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

rp2: fix usb endpoint handling #8040

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ports/rp2/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ set(MICROPY_SOURCE_LIB
${MICROPY_DIR}/lib/oofatfs/ffunicode.c
${MICROPY_DIR}/shared/netutils/netutils.c
${MICROPY_DIR}/shared/readline/readline.c
${MICROPY_DIR}/shared/runtime/interrupt_char.c
${MICROPY_DIR}/shared/runtime/gchelper_m0.s
${MICROPY_DIR}/shared/runtime/gchelper_native.c
${MICROPY_DIR}/shared/runtime/mpirq.c
Expand Down
87 changes: 47 additions & 40 deletions ports/rp2/mphalport.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,49 +29,65 @@
#include "py/mphal.h"
#include "extmod/misc.h"
#include "shared/timeutils/timeutils.h"
#include "shared/runtime/interrupt_char.h"
#include "tusb.h"
#include "uart.h"
#include "hardware/rtc.h"

#if MICROPY_HW_ENABLE_UART_REPL
#if MICROPY_HW_ENABLE_UART_REPL || MICROPY_HW_ENABLE_USBDEV

#ifndef UART_BUFFER_LEN
// reasonably big so we can paste
#define UART_BUFFER_LEN 256
#ifndef MICROPY_HW_STDIN_BUFFER_LEN
#define MICROPY_HW_STDIN_BUFFER_LEN 512
#endif

STATIC uint8_t stdin_ringbuf_array[UART_BUFFER_LEN];
STATIC uint8_t stdin_ringbuf_array[MICROPY_HW_STDIN_BUFFER_LEN];
ringbuf_t stdin_ringbuf = { stdin_ringbuf_array, sizeof(stdin_ringbuf_array) };

#endif

#if MICROPY_KBD_EXCEPTION

int mp_interrupt_char = -1;

void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) {
(void)itf;
(void)wanted_char;
tud_cdc_read_char(); // discard interrupt char
mp_sched_keyboard_interrupt();
#if MICROPY_HW_ENABLE_USBDEV
uint8_t cdc_itf_pending; // keep track of cdc interfaces which needs attention to poll

void poll_cdc_interfaces(void) {
// any CDC interfaces left to poll?
if (cdc_itf_pending && ringbuf_free(&stdin_ringbuf)) {
for (uint8_t itf = 0; itf < 8; ++itf) {
if (cdc_itf_pending & (1 << itf)) {
tud_cdc_rx_cb(itf);
if (!cdc_itf_pending) {
break;
}
}
}
}
}

void mp_hal_set_interrupt_char(int c) {
mp_interrupt_char = c;
tud_cdc_set_wanted_char(c);
void tud_cdc_rx_cb(uint8_t itf) {
// consume pending USB data immediately to free usb buffer and keep the endpoint from stalling.
// in case the ringbuffer is full, mark the CDC interface that need attention later on for polling
cdc_itf_pending &= ~(1 << itf);
for (uint32_t bytes_avail = tud_cdc_n_available(itf); bytes_avail > 0; bytes_avail--) {
if (ringbuf_free(&stdin_ringbuf)) {
int data_char = tud_cdc_read_char();
if (data_char == mp_interrupt_char) {
mp_sched_keyboard_interrupt();
} else {
ringbuf_put(&stdin_ringbuf, data_char);
}
} else {
cdc_itf_pending |= (1 << itf);
return;
}
}
}

#endif
#endif

uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
uintptr_t ret = 0;
#if MICROPY_HW_ENABLE_UART_REPL
if ((poll_flags & MP_STREAM_POLL_RD) && ringbuf_peek(&stdin_ringbuf) != -1) {
ret |= MP_STREAM_POLL_RD;
}
#endif
#if MICROPY_HW_ENABLE_USBDEV
if (tud_cdc_connected() && tud_cdc_available()) {
poll_cdc_interfaces();
#endif
#if MICROPY_HW_ENABLE_UART_REPL || MICROPY_HW_ENABLE_USBDEV
if ((poll_flags & MP_STREAM_POLL_RD) && ringbuf_peek(&stdin_ringbuf) != -1) {
ret |= MP_STREAM_POLL_RD;
}
#endif
Expand All @@ -84,21 +100,14 @@ uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
// Receive single character
int mp_hal_stdin_rx_chr(void) {
for (;;) {
#if MICROPY_HW_ENABLE_UART_REPL
#if MICROPY_HW_ENABLE_USBDEV
poll_cdc_interfaces();
#endif

int c = ringbuf_get(&stdin_ringbuf);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will probably need to check cdc pending here and call tud_cdc_rx_cb, because the poll function may never be called

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hoihu I still think this comment needs attention. If cdc_itf_pending is set then this function may run forever and never check that flag.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dpgeorge I pushed an update. Since mp_hal_stdio_poll() and mp_hal_stdin_rx_chr() share the same logic, I moved the common code to a separate function poll_cdc_interfaces().

8CE4
if (c != -1) {
return c;
}
#endif
#if MICROPY_HW_ENABLE_USBDEV
if (tud_cdc_connected() && tud_cdc_available()) {
uint8_t buf[1];
uint32_t count = tud_cdc_read(buf, sizeof(buf));
if (count) {
return buf[0];
}
}
#endif
#if MICROPY_PY_OS_DUPTERM
int dupterm_c = mp_uos_dupterm_rx_chr();
if (dupterm_c >= 0) {
Expand All @@ -123,11 +132,9 @@ void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
n = CFG_TUD_CDC_EP_BUFSIZE;
}
while (n > tud_cdc_write_available()) {
tud_task();
tud_cdc_write_flush();
MICROPY_EVENT_POLL_HOOK
}
uint32_t n2 = tud_cdc_write(str + i, n);
tud_task();
tud_cdc_write_flush();
i += n2;
}
Expand Down
0