From bca9bc110f3ac8720cbcbf8767f5670099f41519 Mon Sep 17 00:00:00 2001 From: Yaroslav Veremenko Date: Wed, 3 Apr 2024 17:09:30 -0600 Subject: [PATCH] Make USB uart separate from hardware UART Also make hardware UART fully blocking for kput/kprintf --- .../platform/platform-rpipico/CMakeLists.txt | 5 +- Kernel/platform/platform-rpipico/config.h | 13 +- Kernel/platform/platform-rpipico/core1.c | 178 +++++++++++++----- Kernel/platform/platform-rpipico/core1.h | 11 +- Kernel/platform/platform-rpipico/devices.c | 12 +- Kernel/platform/platform-rpipico/devtty.c | 87 ++++++++- Kernel/platform/platform-rpipico/devtty.h | 2 + Kernel/platform/platform-rpipico/main.c | 2 + Kernel/platform/platform-rpipico/mangle.h | 2 + Kernel/platform/platform-rpipico/rawuart.c | 47 +++++ Kernel/platform/platform-rpipico/rawuart.h | 9 + Kernel/platform/platform-rpipico/swapper.c | 2 +- .../platform-rpipico/usbdescriptors.c | 21 ++- 13 files changed, 319 insertions(+), 72 deletions(-) create mode 100644 Kernel/platform/platform-rpipico/rawuart.c create mode 100644 Kernel/platform/platform-rpipico/rawuart.h diff --git a/Kernel/platform/platform-rpipico/CMakeLists.txt b/Kernel/platform/platform-rpipico/CMakeLists.txt index 8dcb7aa290..8bf268a10b 100644 --- a/Kernel/platform/platform-rpipico/CMakeLists.txt +++ b/Kernel/platform/platform-rpipico/CMakeLists.txt @@ -27,6 +27,7 @@ add_executable(fuzix main.c misc.c rawflash.c + rawuart.c swapper.c tricks.S core1.c @@ -70,9 +71,7 @@ target_link_libraries(fuzix pico_multicore hardware_flash hardware_spi - hardware_uart - tinyusb_device_unmarked - tinyusb_board + tinyusb_device ) pico_set_float_implementation(fuzix none) diff --git a/Kernel/platform/platform-rpipico/config.h b/Kernel/platform/platform-rpipico/config.h index f73f63c45e..b56ee96016 100644 --- a/Kernel/platform/platform-rpipico/config.h +++ b/Kernel/platform/platform-rpipico/config.h @@ -1,3 +1,6 @@ +#ifndef CONFIG_H +#define CONFIG_H +#include "tusb_config.h" /* * Set this according to your SD card pins (default * is the David Given arrangement). @@ -48,7 +51,7 @@ #define UDATA_SIZE (UDATA_BLKS << BLKSHIFT) #define USERMEM (160*1024) #define PROGSIZE (65536 - UDATA_SIZE) -extern uint8_t progbase[USERMEM]; +extern char progbase[USERMEM]; #define udata (*(struct u_data*)progbase) #define USERSTACK (4*1024) /* 4kB */ @@ -73,7 +76,12 @@ extern uint8_t progbase[USERMEM]; #define SWAPDEV (swap_dev) /* dynamic swap */ /* Device parameters */ -#define NUM_DEV_TTY 1 +#define NUM_DEV_TTY_UART 1 +#define NUM_DEV_TTY_USB (CFG_TUD_CDC) +#define NUM_DEV_TTY (NUM_DEV_TTY_UART + NUM_DEV_TTY_USB) + +#define USB_TO_TTY(x) (x + 1 + NUM_DEV_TTY_UART) +#define TTY_TO_USB(x) (x - 1 - NUM_DEV_TTY_UART) #define TTYDEV BOOT_TTY /* Device used by kernel for messages, panics */ #define NBUFS 20 /* Number of block buffers */ @@ -91,5 +99,6 @@ extern uint8_t progbase[USERMEM]; #define MANGLED 1 #include "mangle.h" +#endif // vim: sw=4 ts=4 et diff --git a/Kernel/platform/platform-rpipico/core1.c b/Kernel/platform/platform-rpipico/core1.c index d000388421..7b9005615e 100644 --- a/Kernel/platform/platform-rpipico/core1.c +++ b/Kernel/platform/platform-rpipico/core1.c @@ -4,90 +4,178 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include +#include "picosdk.h" +#include "config.h" +#include "core1.h" + #include -#include -#include -#include +#include #include #include #include -#include "core1.h" -bool usbconsole_is_readable(void) +#define CONFIG_CONSOLE_BUF_LEN 16 + +#if CONFIG_CONSOLE_BUF_LEN > 255 +#error "Invalid console buffer length" +#endif + +struct console_buf_t { - return multicore_fifo_rvalid(); + uint8_t buffer[CONFIG_CONSOLE_BUF_LEN]; + uint8_t rindex; + uint8_t windex; + uint8_t len; +}; + +struct console_t +{ + struct console_buf_t rbuf; + struct console_buf_t wbuf; + bool sleeping; +}; + +static struct console_t console_table[NUM_DEV_TTY_USB]; +critical_section_t critical_section; + +static void console_buf_write(struct console_buf_t *buf, uint8_t b) +{ + /* + can deadlock core1 thread + while(buf->len >= CONFIG_CONSOLE_BUF_LEN) + tight_loop_contents(); + */ + critical_section_enter_blocking(&critical_section); + if(buf->len < CONFIG_CONSOLE_BUF_LEN) + { + buf->buffer[buf->windex] = b; + buf->windex = (buf->windex + 1) % CONFIG_CONSOLE_BUF_LEN; + buf->len++; + } + critical_section_exit(&critical_section); } -bool usbconsole_is_writable(void) +static uint8_t console_buf_read(struct console_buf_t *buf) { - return multicore_fifo_wready(); + critical_section_enter_blocking(&critical_section); + if(buf->len == 0) + { + panic("rd undrf"); + } + uint8_t b = buf->buffer[buf->rindex]; + buf->rindex = (buf->rindex + 1) % CONFIG_CONSOLE_BUF_LEN; + buf->len--; + critical_section_exit(&critical_section); + return b; } -uint8_t usbconsole_getc_blocking(void) +int usbconsole_read(uint8_t *buffer, int size) { - return multicore_fifo_pop_blocking(); + if(size & 0x01) + { + panic("buf size"); + } + int written = 0; + for(int i = 0; i < NUM_DEV_TTY && written < size; i++) + { + struct console_buf_t *buf = &console_table[i].rbuf; + if (buf->len > 0) + { + buffer[0] = USB_TO_TTY(i); + buffer[1] = console_buf_read(buf); + buffer += 2; + written += 2; + } + } + return written; } -void usbconsole_putc_blocking(uint8_t b) +extern bool usbconsole_is_writable(uint8_t minor) { - multicore_fifo_push_blocking(b); + minor = TTY_TO_USB(minor); + return console_table[minor].wbuf.len < CONFIG_CONSOLE_BUF_LEN; } -static void core1_main(void) +extern bool usbconsole_is_available(uint8_t minor) { - uart_init(uart_default, PICO_DEFAULT_UART_BAUD_RATE); - gpio_set_function(PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART); - gpio_set_function(PICO_DEFAULT_UART_RX_PIN, GPIO_FUNC_UART); - uart_set_translate_crlf(uart_default, false); - uart_set_fifo_enabled(uart_default, true); + minor = TTY_TO_USB(minor); + return minor <= NUM_DEV_TTY_USB; +} - tusb_init(); +extern void usbconsole_putc(uint8_t minor, uint8_t b) +{ + minor = TTY_TO_USB(minor); + if (minor >= NUM_DEV_TTY_USB) + { + panic("ttydev"); + } + struct console_buf_t *buf = &console_table[minor].wbuf; + if (buf->len >= CONFIG_CONSOLE_BUF_LEN) + { + panic("ovf"); + } + + console_buf_write(buf, b); +} + +extern void usbconsole_setsleep(uint8_t minor, bool sleeping) +{ + console_table[TTY_TO_USB(minor)].sleeping = sleeping; +} + +extern bool usbconsole_is_sleeping(uint8_t minor) +{ + return console_table[TTY_TO_USB(minor)].sleeping; +} + +#if NUM_DEV_TTY_USB > 0 +static void core1_main(void) +{ + tusb_init(); for (;;) { tud_task(); - if (multicore_fifo_rvalid() - && (!tud_cdc_connected() || tud_cdc_write_available()) - && uart_is_writable(uart_default)) - { - int b = multicore_fifo_pop_blocking(); + /* + We ignore tud_cdc_n_connected because if DTR is not set by the host + all tty's will appear disconnected, which seems to be the case for pi pico + */ - if (tud_cdc_connected()) + for(int i = 0; i < CFG_TUD_CDC; i++) + { + if (tud_cdc_n_write_available(i) + && console_table[i].wbuf.len) { - tud_cdc_write(&b, 1); - tud_cdc_write_flush(); + uint8_t b = console_buf_read(&console_table[i].wbuf); + tud_cdc_n_write_char(i, b); + tud_cdc_n_write_flush(i); } - - uart_putc(uart_default, b); } - if (multicore_fifo_wready() - && ((tud_cdc_connected() && tud_cdc_available()) - || uart_is_readable(uart_default))) + for (int i = 0; i < CFG_TUD_CDC; i++) { - /* Only service a byte from CDC *or* the UART, in case two show - * up at the same time and we end up blocking. No big loss, the - * next one will be read the next time around the loop. */ - - if (tud_cdc_available()) + if (!tud_cdc_n_available(i)) { - uint8_t b; - int count = tud_cdc_read(&b, 1); - if (count) - multicore_fifo_push_blocking(b); + continue; } - else if (uart_is_readable(uart_default)) + struct console_buf_t *buf = &console_table[i].rbuf; + if (buf->len < CONFIG_CONSOLE_BUF_LEN) { - uint8_t b = uart_get_hw(uart_default)->dr; - multicore_fifo_push_blocking(b); + uint8_t b = tud_cdc_n_read_char(i); + console_buf_write(buf, b); } } } } +#endif void core1_init(void) { + multicore_reset_core1(); + critical_section_init(&critical_section); +#if NUM_DEV_TTY_USB > 0 multicore_launch_core1(core1_main); +#endif } - diff --git a/Kernel/platform/platform-rpipico/core1.h b/Kernel/platform/platform-rpipico/core1.h index 917991a0bf..26f737480c 100644 --- a/Kernel/platform/platform-rpipico/core1.h +++ b/Kernel/platform/platform-rpipico/core1.h @@ -3,10 +3,13 @@ extern void core1_init(void); -extern bool usbconsole_is_readable(void); -extern bool usbconsole_is_writable(void); -extern uint8_t usbconsole_getc_blocking(void); -extern void usbconsole_putc_blocking(uint8_t b); +extern int usbconsole_read(uint8_t *buffer, int size); +extern bool usbconsole_is_writable(uint8_t minor); +extern bool usbconsole_is_available(uint8_t minor); +extern void usbconsole_putc(uint8_t minor, uint8_t b); +extern void usbconsole_setsleep(uint8_t minor, bool sleeping); +extern bool usbconsole_is_sleeping(uint8_t minor); + #endif diff --git a/Kernel/platform/platform-rpipico/devices.c b/Kernel/platform/platform-rpipico/devices.c index 07841d35ff..302b935501 100644 --- a/Kernel/platform/platform-rpipico/devices.c +++ b/Kernel/platform/platform-rpipico/devices.c @@ -52,14 +52,12 @@ static void timer_tick_cb(unsigned alarm) update_us_since_boot(&next, time_us_64() + (1000000 / TICKSPERSEC)); hardware_alarm_set_target(0, next); } - + irqflags_t irq = di(); + udata.u_ininterrupt = 1; + tty_interrupt(); timer_interrupt(); - - if (usbconsole_is_readable()) - { - uint8_t c = usbconsole_getc_blocking(); - tty_inproc(minor(BOOT_TTY), c); - } + udata.u_ininterrupt = 0; + irqrestore(irq); } void device_init(void) diff --git a/Kernel/platform/platform-rpipico/devtty.c b/Kernel/platform/platform-rpipico/devtty.c index 3bae76b3f9..cd26186c6b 100644 --- a/Kernel/platform/platform-rpipico/devtty.c +++ b/Kernel/platform/platform-rpipico/devtty.c @@ -4,35 +4,84 @@ #include #include #include +#include "rawuart.h" #include "picosdk.h" #include #include "core1.h" -static uint8_t ttybuf[TTYSIZ]; +static uint8_t ttybuf[TTYSIZ*NUM_DEV_TTY]; struct s_queue ttyinq[NUM_DEV_TTY+1] = { /* ttyinq[0] is never used */ { 0, 0, 0, 0, 0, 0 }, - { ttybuf, ttybuf, ttybuf, TTYSIZ, 0, TTYSIZ/2 }, + { &ttybuf[0], &ttybuf[0], &ttybuf[0], TTYSIZ, 0, TTYSIZ/2 }, +#if NUM_DEV_TTY_USB >= 1 + { &ttybuf[TTYSIZ*1], &ttybuf[TTYSIZ*1], &ttybuf[TTYSIZ*1], TTYSIZ, 0, TTYSIZ/2 }, +#endif +#if NUM_DEV_TTY_USB >= 2 + { &ttybuf[TTYSIZ*2], &ttybuf[TTYSIZ*2], &ttybuf[TTYSIZ*2], TTYSIZ, 0, TTYSIZ/2 }, +#endif +#if NUM_DEV_TTY_USB >= 3 + { &ttybuf[TTYSIZ*3], &ttybuf[TTYSIZ*3], &ttybuf[TTYSIZ*3], TTYSIZ, 0, TTYSIZ/2 }, +#endif +#if NUM_DEV_TTY_USB >= 4 + { &ttybuf[TTYSIZ*4], &ttybuf[TTYSIZ*4], &ttybuf[TTYSIZ*4], TTYSIZ, 0, TTYSIZ/2 }, +#endif }; -tcflag_t termios_mask[NUM_DEV_TTY+1] = { 0, _CSYS }; +tcflag_t termios_mask[NUM_DEV_TTY+1] = { + 0, + _CSYS, +#if NUM_DEV_TTY_USB >= 1 + _CSYS, +#endif +#if NUM_DEV_TTY_USB >= 2 + _CSYS, +#endif +#if NUM_DEV_TTY_USB >= 3 + _CSYS, +#endif +#if NUM_DEV_TTY_USB >= 4 + _CSYS, +#endif +}; /* Output for the system console (kprintf etc) */ void kputchar(uint_fast8_t c) { if (c == '\n') - usbconsole_putc_blocking('\r'); - usbconsole_putc_blocking(c); + uart1_putc('\r'); + //usbconsole_putc_blocking(minor(TTYDEV), c); + //usbconsole_putc_debug(c); + uart1_putc(c); } void tty_putc(uint_fast8_t minor, uint_fast8_t c) { - kputchar(c); + + if (minor == 1) + { + uart1_putc(c); + } + else + { + usbconsole_putc(minor, c); + } } ttyready_t tty_writeready(uint_fast8_t minor) { - return usbconsole_is_writable() ? TTY_READY_NOW : TTY_READY_SOON; + if (minor == 1) + { + return uart1_ready() ? TTY_READY_NOW : TTY_READY_SOON; + } + else + { + if (usbconsole_is_writable(minor)) + { + return TTY_READY_NOW; + } + return TTY_READY_SOON; + } } /* For the moment */ @@ -41,9 +90,31 @@ int tty_carrier(uint_fast8_t minor) return 1; } -void tty_sleeping(uint_fast8_t minor) {} +void tty_sleeping(uint_fast8_t minor) +{ + if(minor != 1) + { + usbconsole_setsleep(minor, true); + } +} void tty_data_consumed(uint_fast8_t minor) {} void tty_setup(uint_fast8_t minor, uint_fast8_t flags) {} +void tty_interrupt() +{ + int c; + while ((c = uart1_getc()) >= 0) + { + tty_inproc(1, (char)c); + } +#if NUM_DEV_TTY_USB > 0 + uint8_t cbuf[8]; + int w = usbconsole_read(cbuf, sizeof(cbuf)); + for (int i = 0; i < w; i += 2) + { + tty_inproc(cbuf[i], cbuf[i + 1]); + } +#endif +} /* vim: sw=4 ts=4 et: */ diff --git a/Kernel/platform/platform-rpipico/devtty.h b/Kernel/platform/platform-rpipico/devtty.h index c387e9045b..8870fe1c84 100644 --- a/Kernel/platform/platform-rpipico/devtty.h +++ b/Kernel/platform/platform-rpipico/devtty.h @@ -1,4 +1,6 @@ #ifndef __DEVTTY_DOT_H__ #define __DEVTTY_DOT_H__ +extern void tty_interrupt(); + #endif diff --git a/Kernel/platform/platform-rpipico/main.c b/Kernel/platform/platform-rpipico/main.c index 8108496f07..8b3c590e1b 100644 --- a/Kernel/platform/platform-rpipico/main.c +++ b/Kernel/platform/platform-rpipico/main.c @@ -1,5 +1,6 @@ #include #include +#include "rawuart.h" #include "picosdk.h" #include "kernel-armm0.def" #include "globals.h" @@ -47,6 +48,7 @@ void syscall_handler(struct svc_frame* eh) int main(void) { + uart1_init(); core1_init(); if ((U_DATA__U_SP_OFFSET != offsetof(struct u_data, u_sp)) || diff --git a/Kernel/platform/platform-rpipico/mangle.h b/Kernel/platform/platform-rpipico/mangle.h index a8d3aafe56..4cd125a99a 100644 --- a/Kernel/platform/platform-rpipico/mangle.h +++ b/Kernel/platform/platform-rpipico/mangle.h @@ -3,11 +3,13 @@ #define _read f_read #define _write f_write #define _sbrk f_sbrk + #define ssize_t _ssize_t #else #undef panic #undef _read #undef _write #undef _sbrk + #undef ssize_t #endif #undef MANGLED diff --git a/Kernel/platform/platform-rpipico/rawuart.c b/Kernel/platform/platform-rpipico/rawuart.c new file mode 100644 index 0000000000..f912fece1e --- /dev/null +++ b/Kernel/platform/platform-rpipico/rawuart.c @@ -0,0 +1,47 @@ +#include +#include "picosdk.h" +#include "config.h" +#include "core1.h" + +#include +#include +#include +#include +#include +#include "rawuart.h" + +#if NUM_DEV_TTY_UART != 1 +#error "Only one UART is currently supported" +#endif + +void uart1_init() +{ + uart_init(uart_default, PICO_DEFAULT_UART_BAUD_RATE); + gpio_set_function(PICO_DEFAULT_UART_TX_PIN, GPIO_FUNC_UART); + gpio_set_function(PICO_DEFAULT_UART_RX_PIN, GPIO_FUNC_UART); + uart_set_translate_crlf(uart_default, false); + uart_set_fifo_enabled(uart_default, true); +} + +void uart1_putc(uint8_t c) +{ + while (!uart_is_writable(uart_default)) + { + tight_loop_contents(); + } + uart_putc(uart_default, c); +} + +int uart1_ready() +{ + return uart_is_writable(uart_default); +} + +int uart1_getc() +{ + if (uart_is_readable(uart_default)) + { + return (int)uart_get_hw(uart_default)->dr; + } + return -1; +} \ No newline at end of file diff --git a/Kernel/platform/platform-rpipico/rawuart.h b/Kernel/platform/platform-rpipico/rawuart.h new file mode 100644 index 0000000000..b0a6cbd7e0 --- /dev/null +++ b/Kernel/platform/platform-rpipico/rawuart.h @@ -0,0 +1,9 @@ +#ifndef RAWUART_H +#define RAWUART_H + +extern void uart1_init(); +extern void uart1_putc(uint8_t c); +extern int uart1_ready(); +extern int uart1_getc(); + +#endif \ No newline at end of file diff --git a/Kernel/platform/platform-rpipico/swapper.c b/Kernel/platform/platform-rpipico/swapper.c index 2f736c8426..014ccfafea 100644 --- a/Kernel/platform/platform-rpipico/swapper.c +++ b/Kernel/platform/platform-rpipico/swapper.c @@ -18,7 +18,7 @@ #define BLOCKSIZE 4096 #define NUM_ALLOCATION_BLOCKS (USERMEM / BLOCKSIZE) -uint8_t progbase[USERMEM]; +char progbase[USERMEM]; struct mapentry { diff --git a/Kernel/platform/platform-rpipico/usbdescriptors.c b/Kernel/platform/platform-rpipico/usbdescriptors.c index bb4fae3bec..5cb12da73c 100644 --- a/Kernel/platform/platform-rpipico/usbdescriptors.c +++ b/Kernel/platform/platform-rpipico/usbdescriptors.c @@ -31,11 +31,11 @@ #define USBD_VID (0x2E8A) // Raspberry Pi #define USBD_PID (0x000a) // Raspberry Pi Pico SDK CDC -#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN) +#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + CFG_TUD_CDC * TUD_CDC_DESC_LEN) #define USBD_MAX_POWER_MA (250) #define USBD_ITF_CDC (0) // needs 2 interfaces -#define USBD_ITF_MAX (2) +#define USBD_ITF_MAX (CFG_TUD_CDC*2+1) #define USBD_CDC_EP_CMD (0x81) #define USBD_CDC_EP_OUT (0x02) @@ -50,6 +50,7 @@ #define USBD_STR_CDC (0x04) // Note: descriptors returned from callbacks must exist long enough for transfer to complete +#if CFG_TUD_CDC > 0 static const tusb_desc_device_t usbd_desc_device = { .bLength = sizeof(tusb_desc_device_t), @@ -74,6 +75,21 @@ static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = { TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD, USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, USBD_CDC_IN_OUT_MAX_SIZE), + +#if CFG_TUD_CDC >= 2 + TUD_CDC_DESCRIPTOR(USBD_ITF_CDC+2, USBD_STR_CDC, USBD_CDC_EP_CMD+2, + USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT+2, USBD_CDC_EP_IN+2, USBD_CDC_IN_OUT_MAX_SIZE), +#endif + +#if CFG_TUD_CDC >= 3 + TUD_CDC_DESCRIPTOR(USBD_ITF_CDC+4, USBD_STR_CDC, USBD_CDC_EP_CMD+4, + USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT+4, USBD_CDC_EP_IN+4, USBD_CDC_IN_OUT_MAX_SIZE), +#endif + +#if CFG_TUD_CDC >= 4 + TUD_CDC_DESCRIPTOR(USBD_ITF_CDC+6, USBD_STR_CDC, USBD_CDC_EP_CMD+6, + USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT+6, USBD_CDC_EP_IN+6, USBD_CDC_IN_OUT_MAX_SIZE), +#endif }; static const char *const usbd_desc_str[] = { @@ -116,3 +132,4 @@ const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { return desc_str; } +#endif \ No newline at end of file