Skip to content

Commit

Permalink
prototype
Browse files Browse the repository at this point in the history
  • Loading branch information
alastairpatrick committed Sep 13, 2022
1 parent 98aba25 commit 8a5e920
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/rp2_common/pico_stdio/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ if (NOT TARGET pico_stdio)
${CMAKE_CURRENT_LIST_DIR}/stdio.c
)

target_link_libraries(pico_stdio INTERFACE pico_time)

pico_wrap_function(pico_stdio printf)
pico_wrap_function(pico_stdio vprintf)
pico_wrap_function(pico_stdio puts)
Expand Down
19 changes: 19 additions & 0 deletions src/rp2_common/pico_stdio/include/pico/stdio.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,25 @@
extern "C" {
#endif

#ifndef stdio_yield
#define stdio_yield(delay) busy_wait_us(delay)
#endif

#ifndef stdio_wait
#define stdio_wait() __wfe()
#endif

#ifndef stdio_wait_until
#define stdio_wait_until(until) best_effort_wfe_or_timeout(until)
#endif

#ifndef stdio_signal
#define stdio_signal() __sev();
#endif

#ifndef stdio_signal_from_isr
#define stdio_signal_from_isr() __sev();
#endif

typedef struct stdio_driver stdio_driver_t;

Expand Down
1 change: 1 addition & 0 deletions src/rp2_common/pico_stdio/include/pico/stdio/driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct stdio_driver {
bool last_ended_with_cr;
bool crlf_enabled;
#endif
void (*prepare_to_await_input)(void);
};

#endif
23 changes: 20 additions & 3 deletions src/rp2_common/pico_stdio/stdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ static bool stdio_put_string(const char *s, int len, bool newline, bool no_cr) {

static int stdio_get_until(char *buf, int len, absolute_time_t until) {
do {
bool can_wait = __get_current_exception() == 0;

// todo round robin might be nice on each call, but then again hopefully
// no source will starve the others
for (stdio_driver_t *driver = drivers; driver; driver = driver->next) {
Expand All @@ -136,13 +138,28 @@ static int stdio_get_until(char *buf, int len, absolute_time_t until) {
return read;
}
}
if (!driver->prepare_to_await_input) {
can_wait = false;
}
}
if (time_reached(until)) {
return PICO_ERROR_TIMEOUT;
}
// we sleep here in case the in_chars methods acquire mutexes or disable IRQs and
// potentially starve out what they are waiting on (have seen this with USB)
busy_wait_us(1);

if (can_wait) {
for (stdio_driver_t *driver = drivers; driver; driver = driver->next) {
if (filter && filter != driver) continue;
driver->prepare_to_await_input();
}

stdio_wait_until(until);

// It's tempting to do something here to reverse what prepare_to_await_input() did.
// That would be difficult to do without a race condition though; the other core might
// also be reading from stdio.
} else {
stdio_yield(1);
}
} while (true);
}

Expand Down
3 changes: 3 additions & 0 deletions src/rp2_common/pico_stdio_uart/include/pico/stdio_uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ void stdin_uart_init(void);
*/
void stdio_uart_init_full(uart_inst_t *uart, uint baud_rate, int tx_pin, int rx_pin);

// TODO: document
void stdio_uart_init_blocking(struct uart_inst *uart, uint8_t irq_priority);

#ifdef __cplusplus
}
#endif
Expand Down
42 changes: 42 additions & 0 deletions src/rp2_common/pico_stdio_uart/stdio_uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,20 @@
#include "pico/stdio_uart.h"
#include "pico/binary_info.h"
#include "hardware/gpio.h"
#include "hardware/sync.h"

static uart_inst_t *uart_instance;
static int uart_irq;

#if PICO_NO_BI_STDIO_UART
#define stdio_bi_decl_if_func_used(x)
#else
#define stdio_bi_decl_if_func_used bi_decl_if_func_used
#endif

void uart_interrupt_handler(void);
void uart_prepare_to_await_input(void);

void stdio_uart_init() {
#ifdef uart_default
int tx_pin = -1;
Expand Down Expand Up @@ -76,8 +81,28 @@ void stdio_uart_init_full(struct uart_inst *uart, uint baud_rate, int tx_pin, in
stdio_set_driver_enabled(&stdio_uart, true);
}

void stdio_uart_init_blocking(struct uart_inst *uart, uint8_t irq_priority) {
assert(uart == uart_instance);
uart_irq = uart == uart0 ? UART0_IRQ : UART1_IRQ;

irq_add_shared_handler(uart_irq, uart_interrupt_handler, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
irq_set_priority(uart_irq, irq_priority);
irq_set_enabled(uart_irq, true);

// Was null before to indicate to stdio_get_until() that blocking wasn't supported.
stdio_uart.prepare_to_await_input = uart_prepare_to_await_input;
}

static void stdio_uart_out_chars(const char *buf, int length) {
uart_hw_t* hw = (uart_hw_t*) uart_instance;

for (int i = 0; i <length; i++) {
if (stdio_uart.prepare_to_await_input) {
while (!uart_is_writable(uart_instance)) {
hw_set_bits(&hw->imsc, UART_UARTIMSC_TXIM_BITS);
stdio_wait();
}
}
uart_putc(uart_instance, buf[i]);
}
}
Expand All @@ -90,6 +115,23 @@ int stdio_uart_in_chars(char *buf, int length) {
return i ? i : PICO_ERROR_NO_DATA;
}

void uart_interrupt_handler(void) {
uart_hw_t* hw = (uart_hw_t*) uart_instance;
if (uart_is_readable(uart_instance)) {
hw_clear_bits(&hw->imsc, UART_UARTIMSC_RXIM_BITS | UART_UARTIMSC_RTIM_BITS);
}
if (uart_is_writable(uart_instance)) {
hw_clear_bits(&hw->imsc, UART_UARTIMSC_TXIM_BITS);
}

stdio_signal_from_isr();
}

void uart_prepare_to_await_input(void) {
uart_hw_t* hw = (uart_hw_t*) uart_instance;
hw_set_bits(&hw->imsc, UART_UARTIMSC_RXIM_BITS | UART_UARTIMSC_RTIM_BITS);
}

stdio_driver_t stdio_uart = {
.out_chars = stdio_uart_out_chars,
.in_chars = stdio_uart_in_chars,
Expand Down
5 changes: 5 additions & 0 deletions test/kitchen_sink/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ target_link_libraries(kitchen_sink_cpp kitchen_sink_libs kitchen_sink_options)
pico_set_program_name(kitchen_sink_cpp "Wombat tentacles CPP")
pico_add_extra_outputs(kitchen_sink_cpp)

add_executable(kitchen_sink_uart_stdio ${CMAKE_CURRENT_LIST_DIR}/kitchen_sink.c)
target_link_libraries(kitchen_sink_uart_stdio kitchen_sink_libs kitchen_sink_options)
pico_enable_stdio_uart(kitchen_sink_uart_stdio 1)
pico_add_extra_outputs(kitchen_sink_uart_stdio)

if (TARGET pico_cyw43_arch)
# for lwipopts.h
add_executable(kitchen_sink_lwip_poll ${CMAKE_CURRENT_LIST_DIR}/kitchen_sink.c)
Expand Down
14 changes: 14 additions & 0 deletions test/kitchen_sink/kitchen_sink.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,18 @@ __force_inline int something_inlined(int x) {
auto_init_mutex(mutex);
auto_init_recursive_mutex(recursive_mutex);

void test_stdio(void) {
stdio_uart_init_blocking(uart_default, PICO_LOWEST_IRQ_PRIORITY);
for (;;) {
int c = getchar_timeout_us(1000000);
if (c == PICO_ERROR_TIMEOUT) {
printf("Timeout\n");
} else {
putchar(c);
}
}
}

int main(void) {
spiggle();

Expand All @@ -125,6 +137,8 @@ int main(void) {
puts("Hello Everything!");
puts("Hello Everything2!");

test_stdio();

hard_assert(mutex_try_enter(&mutex, NULL));
hard_assert(!mutex_try_enter(&mutex, NULL));
hard_assert(recursive_mutex_try_enter(&recursive_mutex, NULL));
Expand Down

0 comments on commit 8a5e920

Please sign in to comment.