8000 ports(rp2): Fix usb endpoint handling. · micropython/micropython@8496f25 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8496f25

Browse files
committed
ports(rp2): Fix usb endpoint handling.
The CDC USB endpoint got NACK'd if a character was received but not consumed by the application (e.g. via sys.stdin.read()). See also issue #7996. This approach uses a callback `tud_cdc_rx_cb` which is called by the tinyUSB stack on reception of new cdc data. By consuming the data immediately, the endpoint does not stall anymore. The previous handler `tud_cdc_rx_wanted_cb` was obsolete and removed. In addition some cleanup was done along the way: by adding `interrupt_char.c` and removing the existing code `mp_hal_set_interrupt_char()`. Also, there is now only one (stdin) ringbuffer.
1 parent 94a9b50 commit 8496f25

File tree

2 files changed

+48
-40
lines changed

2 files changed

+48
-40
lines changed

ports/rp2/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ set(MICROPY_SOURCE_LIB
6868
${MICROPY_DIR}/lib/oofatfs/ffunicode.c
6969
${MICROPY_DIR}/shared/netutils/netutils.c
7070
${MICROPY_DIR}/shared/readline/readline.c
71+
${MICROPY_DIR}/shared/runtime/interrupt_char.c
7172
${MICROPY_DIR}/shared/runtime/gchelper_m0.s
7273
${MICROPY_DIR}/shared/runtime/gchelper_native.c
7374
${MICROPY_DIR}/shared/runtime/mpirq.c

ports/rp2/mphalport.c

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -29,49 +29,65 @@
2929
#include "py/mphal.h"
3030
#include "extmod/misc.h"
3131
#include "shared/timeutils/timeutils.h"
32+
#include "shared/runtime/interrupt_char.h"
3233
#include "tusb.h"
3334
#include "uart.h"
3435
#include "hardware/rtc.h"
3536

36-
#if MICROPY_HW_ENABLE_UART_REPL
37+
#if MICROPY_HW_ENABLE_UART_REPL || MICROPY_HW_ENABLE_USBDEV
3738

38-
#ifndef UART_BUFFER_LEN
39-
// reasonably big so we can paste
40-
#define UART_BUFFER_LEN 256
39+
#ifndef MICROPY_HW_STDIN_BUFFER_LEN
40+
#define MICROPY_HW_STDIN_BUFFER_LEN 512
4141
#endif
4242

43-
STATIC uint8_t stdin_ringbuf_array[UART_BUFFER_LEN];
43+
STATIC uint8_t stdin_ringbuf_array[MICROPY_HW_STDIN_BUFFER_LEN];
4444
ringbuf_t stdin_ringbuf = { stdin_ringbuf_array, sizeof(stdin_ringbuf_array) };
4545

46-
#endif
47-
48-
#if MICROPY_KBD_EXCEPTION
49-
50-
int mp_interrupt_char = -1;
51-
52-
void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) {
53-
(void)itf;
54-
(void)wanted_char;
55-
tud_cdc_read_char(); // discard interrupt char
56-
mp_sched_keyboard_interrupt();
46+
#if MICROPY_HW_ENABLE_USBDEV
47+
uint8_t cdc_itf_pending; // keep track of cdc interfaces which needs attention to poll
48+
49+
void poll_cdc_interfaces(void) {
50+
// any CDC interfaces left to poll?
51+
if (cdc_itf_pending && ringbuf_free(&stdin_ringbuf)) {
52+
for (uint8_t itf = 0; itf < 8; ++itf) {
53+
if (cdc_itf_pending & (1 << itf)) {
54+
tud_cdc_rx_cb(itf);
55+
if (!cdc_itf_pending) {
56+
break;
57+
}
58+
}
59+
}
60+
}
5761
}
5862

59-
void mp_hal_set_interrupt_char(int c) {
60-
mp_interrupt_char = c;
61-
tud_cdc_set_wanted_char(c);
63+
void tud_cdc_rx_cb(uint8_t itf) {
64+
// consume pending USB data immediately to free usb buffer and keep the endpoint from stalling.
65+
// in case the ringbuffer is full, mark the CDC interface that need attention later on for polling
66+
cdc_itf_pending &= ~(1 << itf);
67+
for (uint32_t bytes_avail = tud_cdc_n_available(itf); bytes_avail > 0; bytes_avail--) {
68+
if (ringbuf_free(&stdin_ringbuf)) {
69+
int data_char = tud_cdc_read_char();
70+
if (data_char == mp_interrupt_char) {
71+
mp_sched_keyboard_interrupt();
72+
} else {
73+
ringbuf_put(&stdin_ringbuf, data_char);
74+
}
75+
} else {
76+
cdc_itf_pending |= (1 << itf);
77+
return;
78+
}
79+
}
6280
}
63-
81+
#endif
6482
#endif
6583

6684
uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
6785
uintptr_t ret = 0;
68-
#if MICROPY_HW_ENABLE_UART_REPL
69-
if ((poll_flags & MP_STREAM_POLL_RD) && ringbuf_peek(&stdin_ringbuf) != -1) {
70-
ret |= MP_STREAM_POLL_RD;
71-
}
72-
#endif
7386
#if MICROPY_HW_ENABLE_USBDEV
74-
if (tud_cdc_connected() && tud_cdc_available()) {
87+
poll_cdc_interfaces();
88+
#endif
89+
#if MICROPY_HW_ENABLE_UART_REPL || MICROPY_HW_ENABLE_USBDEV
90+
if ((poll_flags & MP_STREAM_POLL_RD) && ringbuf_peek(&stdin_ringbuf) != -1) {
7591
ret |= MP_STREAM_POLL_RD;
7692
}
7793
#endif
@@ -84,21 +100,14 @@ uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
84100
// Receive single character
85101
int mp_hal_stdin_rx_chr(void) {
86102
for (;;) {
87-
#if MICROPY_HW_ENABLE_UART_REPL
103+
#if MICROPY_HW_ENABLE_USBDEV
104+
poll_cdc_interfaces();
105+
#endif
106+
88107
int c = ringbuf_get(&stdin_ringbuf);
89108
if (c != -1) {
90109
return c;
91110
}
92-
#endif
93-
#if MICROPY_HW_ENABLE_USBDEV
94-
if (tud_cdc_connected() && tud_cdc_available()) {
95-
uint8_t buf[1];
96-
uint32_t count = tud_cdc_read(buf, sizeof(buf));
97-
if (count) {
98-
return buf[0];
99-
}
100-
}
101-
#endif
102111
#if MICROPY_PY_OS_DUPTERM
103112
int dupterm_c = mp_uos_dupterm_rx_chr();
104113
if (dupterm_c >= 0) {
@@ -123,11 +132,9 @@ void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
123132
n = CFG_TUD_CDC_EP_BUFSIZE;
124133
}
125134
while (n > tud_cdc_write_available()) {
126-
tud_task();
127-
tud_cdc_write_flush();
135+
MICROPY_EVENT_POLL_HOOK
128136
}
129137
uint32_t n2 = tud_cdc_write(str + i, n);
130-
tud_task();
131138
tud_cdc_write_flush();
132139
i += n2;
133140
}

0 commit comments

Comments
 (0)
0