From ca8aea1a625abf45b4b4e40d1c109948b3c46134 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Wed, 26 Sep 2018 21:09:28 +0300 Subject: [PATCH] subsys: console: Split serial tty handling to a separate module Before going further for API refactoring in console subsys, makes sense to split "tty" implementation from "console" implementation, to make it clearer that "console" is just a "tty" instantiated on a particular UART device. Signed-off-by: Paul Sokolovsky --- include/console.h | 50 +++++++++++++ subsys/console/CMakeLists.txt | 2 +- subsys/console/getchar.c | 135 +--------------------------------- subsys/console/tty.c | 125 +++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 133 deletions(-) create mode 100644 subsys/console/tty.c diff --git a/include/console.h b/include/console.h index a7641695d7..437609fe3c 100644 --- a/include/console.h +++ b/include/console.h @@ -14,6 +14,56 @@ extern "C" { #endif +struct tty_serial { + struct device *uart_dev; + + struct k_sem rx_sem; + u8_t *rx_ringbuf; + u32_t rx_ringbuf_sz; + u16_t rx_get, rx_put; + + u8_t *tx_ringbuf; + u32_t tx_ringbuf_sz; + u16_t tx_get, tx_put; +}; + +/** + * @brief Initialize buffered serial port (classically known as tty). + * + * "tty" device provides buffered, interrupt-driver access to an + * underlying UART device. + * + * @param tty tty device structure to initialize + * @param uart_dev underlying UART device to use (should support + * interrupt-driven operation) + * @param rxbuf pointer to receive buffer + * @param rxbuf_sz size of receive buffer + * @param txbuf pointer to transmit buffer + * @param txbuf_sz size of transmit buffer + * + * @return N/A + */ +void tty_init(struct tty_serial *tty, struct device *uart_dev, + u8_t *rxbuf, u16_t rxbuf_sz, + u8_t *txbuf, u16_t txbuf_sz); + + +/** + * @brief Input a character from a tty device. + * + * @param tty tty device structure + */ +u8_t tty_getchar(struct tty_serial *tty); + +/** + * @brief Output a character from to tty device. + * + * @param tty tty device structure + * @param c character to output + * @return 0 if ok, <0 if error + */ +int tty_putchar(struct tty_serial *tty, u8_t c); + /** @brief Initialize console_getchar()/putchar() calls. * * This function should be called once to initialize pull-style diff --git a/subsys/console/CMakeLists.txt b/subsys/console/CMakeLists.txt index f56de0b0db..6fd94b81a5 100644 --- a/subsys/console/CMakeLists.txt +++ b/subsys/console/CMakeLists.txt @@ -1,3 +1,3 @@ zephyr_sources(line_fifo.c) -zephyr_sources_ifdef(CONFIG_CONSOLE_GETCHAR getchar.c) +zephyr_sources_ifdef(CONFIG_CONSOLE_GETCHAR tty.c getchar.c) zephyr_sources_ifdef(CONFIG_CONSOLE_GETLINE getline.c) diff --git a/subsys/console/getchar.c b/subsys/console/getchar.c index 564f99c5cc..6b36d12a35 100644 --- a/subsys/console/getchar.c +++ b/subsys/console/getchar.c @@ -5,146 +5,17 @@ */ #include -#include -#include +#include #include -#include -#include -struct tty_serial { - struct device *uart_dev; - - struct k_sem rx_sem; - u8_t *rx_ringbuf; - u32_t rx_ringbuf_sz; - u16_t rx_get, rx_put; - - u8_t *tx_ringbuf; - u32_t tx_ringbuf_sz; - u16_t tx_get, tx_put; -}; +static struct tty_serial console_serial; static u8_t console_rxbuf[CONFIG_CONSOLE_GETCHAR_BUFSIZE]; static u8_t console_txbuf[CONFIG_CONSOLE_PUTCHAR_BUFSIZE]; -static int tty_irq_input_hook(struct tty_serial *tty, u8_t c); - -static struct tty_serial console_serial; - -static void tty_uart_isr(void *user_data) -{ - struct tty_serial *tty = user_data; - struct device *dev = tty->uart_dev; - - uart_irq_update(dev); - - if (uart_irq_rx_ready(dev)) { - u8_t c; - - while (1) { - if (uart_fifo_read(dev, &c, 1) == 0) { - break; - } - tty_irq_input_hook(tty, c); - } - } - - if (uart_irq_tx_ready(dev)) { - if (tty->tx_get == tty->tx_put) { - /* Output buffer empty, don't bother - * us with tx interrupts - */ - uart_irq_tx_disable(dev); - } else { - uart_fifo_fill(dev, &tty->tx_ringbuf[tty->tx_get++], 1); - if (tty->tx_get >= tty->tx_ringbuf_sz) { - tty->tx_get = 0; - } - } - } -} - -static int tty_irq_input_hook(struct tty_serial *tty, u8_t c) -{ - int rx_next = tty->rx_put + 1; - if (rx_next >= tty->rx_ringbuf_sz) { - rx_next = 0; - } - - if (rx_next == tty->rx_get) { - /* Try to give a clue to user that some input was lost */ - console_putchar('~'); - console_putchar('\n'); - return 1; - } - - tty->rx_ringbuf[tty->rx_put] = c; - tty->rx_put = rx_next; - k_sem_give(&tty->rx_sem); - - return 1; -} - -int tty_putchar(struct tty_serial *tty, char c) -{ - unsigned int key; - int tx_next; - - key = irq_lock(); - tx_next = tty->tx_put + 1; - if (tx_next >= tty->tx_ringbuf_sz) { - tx_next = 0; - } - if (tx_next == tty->tx_get) { - irq_unlock(key); - return -1; - } - - tty->tx_ringbuf[tty->tx_put] = (u8_t)c; - tty->tx_put = tx_next; - - irq_unlock(key); - uart_irq_tx_enable(tty->uart_dev); - return 0; -} - -u8_t tty_getchar(struct tty_serial *tty) -{ - unsigned int key; - u8_t c; - - k_sem_take(&tty->rx_sem, K_FOREVER); - - key = irq_lock(); - c = tty->rx_ringbuf[tty->rx_get++]; - if (tty->rx_get >= tty->rx_ringbuf_sz) { - tty->rx_get = 0; - } - irq_unlock(key); - - return c; -} - -void tty_init(struct tty_serial *tty, struct device *uart_dev, - u8_t *rxbuf, u16_t rxbuf_sz, - u8_t *txbuf, u16_t txbuf_sz) -{ - tty->uart_dev = uart_dev; - tty->rx_ringbuf = rxbuf; - tty->rx_ringbuf_sz = rxbuf_sz; - tty->tx_ringbuf = txbuf; - tty->tx_ringbuf_sz = txbuf_sz; - tty->rx_get = tty->rx_put = tty->tx_get = tty->tx_put = 0; - k_sem_init(&tty->rx_sem, 0, UINT_MAX); - - uart_irq_callback_user_data_set(uart_dev, tty_uart_isr, tty); - uart_irq_rx_enable(uart_dev); -} - - int console_putchar(char c) { - return tty_putchar(&console_serial, c); + return tty_putchar(&console_serial, (u8_t)c); } u8_t console_getchar(void) diff --git a/subsys/console/tty.c b/subsys/console/tty.c new file mode 100644 index 0000000000..5f004f542b --- /dev/null +++ b/subsys/console/tty.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2018 Linaro Limited. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +static int tty_irq_input_hook(struct tty_serial *tty, u8_t c); + +static void tty_uart_isr(void *user_data) +{ + struct tty_serial *tty = user_data; + struct device *dev = tty->uart_dev; + + uart_irq_update(dev); + + if (uart_irq_rx_ready(dev)) { + u8_t c; + + while (1) { + if (uart_fifo_read(dev, &c, 1) == 0) { + break; + } + tty_irq_input_hook(tty, c); + } + } + + if (uart_irq_tx_ready(dev)) { + if (tty->tx_get == tty->tx_put) { + /* Output buffer empty, don't bother + * us with tx interrupts + */ + uart_irq_tx_disable(dev); + } else { + uart_fifo_fill(dev, &tty->tx_ringbuf[tty->tx_get++], 1); + if (tty->tx_get >= tty->tx_ringbuf_sz) { + tty->tx_get = 0; + } + } + } +} + +static int tty_irq_input_hook(struct tty_serial *tty, u8_t c) +{ + int rx_next = tty->rx_put + 1; + + if (rx_next >= tty->rx_ringbuf_sz) { + rx_next = 0; + } + + if (rx_next == tty->rx_get) { + /* Try to give a clue to user that some input was lost */ + console_putchar('~'); + console_putchar('\n'); + return 1; + } + + tty->rx_ringbuf[tty->rx_put] = c; + tty->rx_put = rx_next; + k_sem_give(&tty->rx_sem); + + return 1; +} + +int tty_putchar(struct tty_serial *tty, u8_t c) +{ + unsigned int key; + int tx_next; + + key = irq_lock(); + tx_next = tty->tx_put + 1; + if (tx_next >= tty->tx_ringbuf_sz) { + tx_next = 0; + } + if (tx_next == tty->tx_get) { + irq_unlock(key); + return -1; + } + + tty->tx_ringbuf[tty->tx_put] = c; + tty->tx_put = tx_next; + + irq_unlock(key); + uart_irq_tx_enable(tty->uart_dev); + return 0; +} + +u8_t tty_getchar(struct tty_serial *tty) +{ + unsigned int key; + u8_t c; + + k_sem_take(&tty->rx_sem, K_FOREVER); + + key = irq_lock(); + c = tty->rx_ringbuf[tty->rx_get++]; + if (tty->rx_get >= tty->rx_ringbuf_sz) { + tty->rx_get = 0; + } + irq_unlock(key); + + return c; +} + +void tty_init(struct tty_serial *tty, struct device *uart_dev, + u8_t *rxbuf, u16_t rxbuf_sz, + u8_t *txbuf, u16_t txbuf_sz) +{ + tty->uart_dev = uart_dev; + tty->rx_ringbuf = rxbuf; + tty->rx_ringbuf_sz = rxbuf_sz; + tty->tx_ringbuf = txbuf; + tty->tx_ringbuf_sz = txbuf_sz; + tty->rx_get = tty->rx_put = tty->tx_get = tty->tx_put = 0; + k_sem_init(&tty->rx_sem, 0, UINT_MAX); + + uart_irq_callback_user_data_set(uart_dev, tty_uart_isr, tty); + uart_irq_rx_enable(uart_dev); +}