From 31780aed2cad539f7afa902b9561cae751fcfc40 Mon Sep 17 00:00:00 2001 From: Peter Harper <77111776+peterharperuk@users.noreply.github.com> Date: Tue, 31 Jan 2023 21:47:36 +0000 Subject: [PATCH] Add stdio_set_chars_available_callback (#1213) There's currently no way to be notified in a "stdio" agnostic way whether there's an incoming character available. You can poll with getchar_timeout_us, but that's far from ideal. Add a method that takes a callback to notify that a character might be available. --- .../pico_stdio/include/pico/stdio.h | 8 ++++ .../pico_stdio/include/pico/stdio/driver.h | 1 + src/rp2_common/pico_stdio/stdio.c | 8 +++- .../pico_stdio_uart/include/pico/stdio_uart.h | 5 +++ src/rp2_common/pico_stdio_uart/stdio_uart.c | 40 +++++++++++++++++++ .../pico_stdio_usb/include/pico/stdio_usb.h | 5 +++ src/rp2_common/pico_stdio_usb/stdio_usb.c | 22 ++++++++++ 7 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/rp2_common/pico_stdio/include/pico/stdio.h b/src/rp2_common/pico_stdio/include/pico/stdio.h index ebae386..205473b 100644 --- a/src/rp2_common/pico_stdio/include/pico/stdio.h +++ b/src/rp2_common/pico_stdio/include/pico/stdio.h @@ -109,6 +109,14 @@ int putchar_raw(int c); */ int puts_raw(const char *s); +/*! \brief get notified when there are input characters available + * \ingroup pico_stdio + * + * \param fn Callback function to be called when characters are available. Pass NULL to cancel any existing callback + * \param param Pointer to pass to the callback + */ +void stdio_set_chars_available_callback(void (*fn)(void*), void *param); + #ifdef __cplusplus } #endif diff --git a/src/rp2_common/pico_stdio/include/pico/stdio/driver.h b/src/rp2_common/pico_stdio/include/pico/stdio/driver.h index f85ed8a..9ed1ebd 100644 --- a/src/rp2_common/pico_stdio/include/pico/stdio/driver.h +++ b/src/rp2_common/pico_stdio/include/pico/stdio/driver.h @@ -13,6 +13,7 @@ struct stdio_driver { void (*out_chars)(const char *buf, int len); void (*out_flush)(void); int (*in_chars)(char *buf, int len); + void (*set_chars_available_callback)(void (*fn)(void*), void *param); stdio_driver_t *next; #if PICO_STDIO_ENABLE_CRLF_SUPPORT bool last_ended_with_cr; diff --git a/src/rp2_common/pico_stdio/stdio.c b/src/rp2_common/pico_stdio/stdio.c index c472560..22aea46 100644 --- a/src/rp2_common/pico_stdio/stdio.c +++ b/src/rp2_common/pico_stdio/stdio.c @@ -345,4 +345,10 @@ void stdio_set_translate_crlf(stdio_driver_t *driver, bool enabled) { panic_unsupported(); #endif -} \ No newline at end of file +} + +void stdio_set_chars_available_callback(void (*fn)(void*), void *param) { + for (stdio_driver_t *s = drivers; s; s = s->next) { + if (s->set_chars_available_callback) s->set_chars_available_callback(fn, param); + } +} diff --git a/src/rp2_common/pico_stdio_uart/include/pico/stdio_uart.h b/src/rp2_common/pico_stdio_uart/include/pico/stdio_uart.h index 9e5ac53..70b302e 100644 --- a/src/rp2_common/pico_stdio_uart/include/pico/stdio_uart.h +++ b/src/rp2_common/pico_stdio_uart/include/pico/stdio_uart.h @@ -23,6 +23,11 @@ #define PICO_STDIO_UART_DEFAULT_CRLF PICO_STDIO_DEFAULT_CRLF #endif +// PICO_CONFIG: PICO_STDIO_UART_SUPPORT_CHARS_AVAILABLE_CALLBACK, Enable UART STDIO support for stdio_set_chars_available_callback. Can be disabled to make use of the uart elsewhere, type=bool default=1, group=pico_stdio_uart +#ifndef PICO_STDIO_UART_SUPPORT_CHARS_AVAILABLE_CALLBACK +#define PICO_STDIO_UART_SUPPORT_CHARS_AVAILABLE_CALLBACK 1 +#endif + #ifdef __cplusplus extern "C" { #endif diff --git a/src/rp2_common/pico_stdio_uart/stdio_uart.c b/src/rp2_common/pico_stdio_uart/stdio_uart.c index ccdf202..c77bb47 100644 --- a/src/rp2_common/pico_stdio_uart/stdio_uart.c +++ b/src/rp2_common/pico_stdio_uart/stdio_uart.c @@ -11,6 +11,11 @@ static uart_inst_t *uart_instance; +#if PICO_STDIO_UART_SUPPORT_CHARS_AVAILABLE_CALLBACK +static void (*chars_available_callback)(void*); +static void *chars_available_param; +#endif + #if PICO_NO_BI_STDIO_UART #define stdio_bi_decl_if_func_used(x) #else @@ -87,12 +92,47 @@ int stdio_uart_in_chars(char *buf, int length) { while (i= NUM_IRQS - NUM_USER_IRQS, ""); #else static uint8_t low_priority_irq_num; #endif +#if PICO_STDIO_USB_SUPPORT_CHARS_AVAILABLE_CALLBACK +static void (*chars_available_callback)(void*); +static void *chars_available_param; +#endif static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) { int64_t repeat_time; @@ -137,12 +142,29 @@ int stdio_usb_in_chars(char *buf, int length) { return rc; } +#if PICO_STDIO_USB_SUPPORT_CHARS_AVAILABLE_CALLBACK +void tud_cdc_rx_cb(__unused uint8_t itf) { + if (chars_available_callback) { + usbd_defer_func(chars_available_callback, chars_available_param, false); + } +} + +void stdio_usb_set_chars_available_callback(void (*fn)(void*), void *param) { + chars_available_callback = fn; + chars_available_param = param; +} +#endif + stdio_driver_t stdio_usb = { .out_chars = stdio_usb_out_chars, .in_chars = stdio_usb_in_chars, +#if PICO_STDIO_USB_SUPPORT_CHARS_AVAILABLE_CALLBACK + .set_chars_available_callback = stdio_usb_set_chars_available_callback, +#endif #if PICO_STDIO_ENABLE_CRLF_SUPPORT .crlf_enabled = PICO_STDIO_USB_DEFAULT_CRLF #endif + }; bool stdio_usb_init(void) {