From df5c876932c4c82e8aee32adca651bb99d9d6200 Mon Sep 17 00:00:00 2001 From: zhangwenjian Date: Thu, 23 May 2024 13:13:48 +0800 Subject: [PATCH] libc:getline support backspace Signed-off-by: zhangwenjian --- drivers/serial/pty.c | 2 +- drivers/serial/serial.c | 63 ++++++++++++++++++++++++++++++++--------- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/drivers/serial/pty.c b/drivers/serial/pty.c index bc37f9050de..92cbd06e5ac 100644 --- a/drivers/serial/pty.c +++ b/drivers/serial/pty.c @@ -1074,7 +1074,7 @@ int pty_register2(int minor, bool susv1) devpair->pp_master.pd_oflag = OPOST | OCRNL; devpair->pp_slave.pd_devpair = devpair; devpair->pp_slave.pd_oflag = OPOST | ONLCR; - devpair->pp_slave.pd_lflag = ECHO; + devpair->pp_slave.pd_lflag = ECHO | ICANON; #if defined(CONFIG_TTY_SIGINT) || defined(CONFIG_TTY_SIGTSTP) /* Initialize of the task that will receive SIGINT signals. */ diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index b881f5d4709..a274b0e41c3 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -909,6 +909,25 @@ static ssize_t uart_read(FAR struct file *filep, } } + if ((dev->tc_lflag & ICANON) && + (ch == ASCII_BS || ch == ASCII_DEL)) + { + if (recvd > 0) + { + *buffer-- = '\0'; + recvd--; + if (dev->tc_lflag & ECHO) + { + uart_putxmitchar(dev, '\b', true); + uart_putxmitchar(dev, ' ', true); + uart_putxmitchar(dev, '\b', true); + echoed = true; + } + } + + continue; + } + /* Specifically not handled: * * All of the local modes; echo, line editing, etc. @@ -967,6 +986,11 @@ static ssize_t uart_read(FAR struct file *filep, echoed = true; } } + + if ((dev->tc_lflag & ICANON) && ch == '\n') + { + break; + } } #ifdef CONFIG_DEV_SERIAL_FULLBLOCKS @@ -993,7 +1017,7 @@ static ssize_t uart_read(FAR struct file *filep, * to the caller? */ - else if (recvd > 0) + else if (recvd > 0 && !(dev->tc_lflag & ICANON)) { /* Yes.. break out of the loop and return the number of bytes * received up to the wait condition. @@ -1095,26 +1119,39 @@ static ssize_t uart_read(FAR struct file *filep, * thread goes to sleep. */ + if (dev->tc_lflag & ICANON) + { #ifdef CONFIG_SERIAL_TERMIOS - dev->minrecv = MIN(buflen - recvd, dev->minread - recvd); - if (dev->timeout) - { - nxmutex_unlock(&dev->recv.lock); - ret = nxsem_tickwait(&dev->recvsem, - DSEC2TICK(dev->timeout)); - } - else + dev->minrecv = 0; #endif - { nxmutex_unlock(&dev->recv.lock); ret = nxsem_wait(&dev->recvsem); + nxmutex_lock(&dev->recv.lock); } + else + { +#ifdef CONFIG_SERIAL_TERMIOS + dev->minrecv = MIN(buflen - recvd, + dev->minread - recvd); + if (dev->timeout) + { + nxmutex_unlock(&dev->recv.lock); + ret = nxsem_tickwait(&dev->recvsem, + DSEC2TICK(dev->timeout)); + } + else +#endif + { + nxmutex_unlock(&dev->recv.lock); + ret = nxsem_wait(&dev->recvsem); + } - nxmutex_lock(&dev->recv.lock); + nxmutex_lock(&dev->recv.lock); #ifdef CONFIG_SERIAL_TERMIOS - dev->minrecv = dev->minread; + dev->minrecv = dev->minread; #endif + } } leave_critical_section(flags); @@ -1924,7 +1961,7 @@ int uart_register(FAR const char *path, FAR uart_dev_t *dev) { /* Enable signals and echo by default */ - dev->tc_lflag |= ISIG | ECHO; + dev->tc_lflag |= ISIG | ECHO | ICANON; /* Enable \n -> \r\n translation for the console */