From 039efbb075120a1718dfe9b171432744d90e9bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E5=A4=A9=E9=BE=99=20=28Armink=29?= Date: Mon, 4 Apr 2022 17:25:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=20Serial=20V2=20=E6=A1=86?= =?UTF-8?q?=E6=9E=B6=20(#5770)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [stm32] fix h7 uart V2 driver unused code. * [DeviceDriver][serialv2] fix the serialv2 when using for console device on DMA mode. * [stm32][art-pi] using serial v2 by default * [DeviceDriver][SerialV2] Add termios for serial@V2 . * [BSP][STM32] Add hardware flow control for STM32 serial@V2 driver. * [DeviceDriver][Serial@V2] Add hardware flow control for serial V2. --- .../libraries/HAL_Drivers/drv_usart_v2.c | 14 +- .../drivers/include/drivers/serial_v2.h | 33 +- components/drivers/serial/serial_v2.c | 301 ++++++++++++++++++ 3 files changed, 333 insertions(+), 15 deletions(-) diff --git a/bsp/stm32/libraries/HAL_Drivers/drv_usart_v2.c b/bsp/stm32/libraries/HAL_Drivers/drv_usart_v2.c index b399f0818a..79247b9e3e 100644 --- a/bsp/stm32/libraries/HAL_Drivers/drv_usart_v2.c +++ b/bsp/stm32/libraries/HAL_Drivers/drv_usart_v2.c @@ -119,7 +119,6 @@ static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_c uart->handle.Instance = uart->config->Instance; uart->handle.Init.BaudRate = cfg->baud_rate; - uart->handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; uart->handle.Init.Mode = UART_MODE_TX_RX; uart->handle.Init.OverSampling = UART_OVERSAMPLING_16; @@ -168,6 +167,19 @@ static rt_err_t stm32_configure(struct rt_serial_device *serial, struct serial_c break; } + switch (cfg->flowcontrol) + { + case RT_SERIAL_FLOWCONTROL_NONE: + uart->handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; + break; + case RT_SERIAL_FLOWCONTROL_CTSRTS: + uart->handle.Init.HwFlowCtl = UART_HWCONTROL_RTS_CTS; + break; + default: + uart->handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; + break; + } + #ifdef RT_SERIAL_USING_DMA uart->dma_rx.remaining_cnt = serial->config.rx_bufsz; #endif diff --git a/components/drivers/include/drivers/serial_v2.h b/components/drivers/include/drivers/serial_v2.h index e85bdecf51..e0c469423b 100644 --- a/components/drivers/include/drivers/serial_v2.h +++ b/components/drivers/include/drivers/serial_v2.h @@ -80,21 +80,25 @@ #define RT_SERIAL_RX_MINBUFSZ 64 #define RT_SERIAL_TX_MINBUFSZ 64 -#define RT_SERIAL_TX_BLOCKING_BUFFER 1 -#define RT_SERIAL_TX_BLOCKING_NO_BUFFER 0 +#define RT_SERIAL_TX_BLOCKING_BUFFER 1 +#define RT_SERIAL_TX_BLOCKING_NO_BUFFER 0 + +#define RT_SERIAL_FLOWCONTROL_CTSRTS 1 +#define RT_SERIAL_FLOWCONTROL_NONE 0 /* Default config for serial_configure structure */ -#define RT_SERIAL_CONFIG_DEFAULT \ -{ \ - BAUD_RATE_115200, /* 115200 bits/s */ \ - DATA_BITS_8, /* 8 databits */ \ - STOP_BITS_1, /* 1 stopbit */ \ - PARITY_NONE, /* No parity */ \ - BIT_ORDER_LSB, /* LSB first sent */ \ - NRZ_NORMAL, /* Normal mode */ \ - RT_SERIAL_RX_MINBUFSZ, /* rxBuf size */ \ - RT_SERIAL_TX_MINBUFSZ, /* txBuf size */ \ - 0 \ +#define RT_SERIAL_CONFIG_DEFAULT \ +{ \ + BAUD_RATE_115200, /* 115200 bits/s */ \ + DATA_BITS_8, /* 8 databits */ \ + STOP_BITS_1, /* 1 stopbit */ \ + PARITY_NONE, /* No parity */ \ + BIT_ORDER_LSB, /* LSB first sent */ \ + NRZ_NORMAL, /* Normal mode */ \ + RT_SERIAL_RX_MINBUFSZ, /* rxBuf size */ \ + RT_SERIAL_TX_MINBUFSZ, /* txBuf size */ \ + RT_SERIAL_FLOWCONTROL_NONE, /* Off flowcontrol */ \ + 0 \ } struct serial_configure @@ -108,7 +112,8 @@ struct serial_configure rt_uint32_t invert :1; rt_uint32_t rx_bufsz :16; rt_uint32_t tx_bufsz :16; - rt_uint32_t reserved :6; + rt_uint32_t flowcontrol :1; + rt_uint32_t reserved :5; }; /* diff --git a/components/drivers/serial/serial_v2.c b/components/drivers/serial/serial_v2.c index 7a7a04de35..17a37a9a3e 100644 --- a/components/drivers/serial/serial_v2.c +++ b/components/drivers/serial/serial_v2.c @@ -23,6 +23,10 @@ #include #include +#ifdef RT_USING_POSIX_TERMIOS +#include +#endif + #ifdef getc #undef getc #endif @@ -984,6 +988,98 @@ static rt_err_t rt_serial_close(struct rt_device *dev) return RT_EOK; } +#ifdef RT_USING_POSIX_TERMIOS +struct speed_baudrate_item +{ + speed_t speed; + int baudrate; +}; + +const static struct speed_baudrate_item _tbl[] = +{ + {B2400, BAUD_RATE_2400}, + {B4800, BAUD_RATE_4800}, + {B9600, BAUD_RATE_9600}, + {B19200, BAUD_RATE_19200}, + {B38400, BAUD_RATE_38400}, + {B57600, BAUD_RATE_57600}, + {B115200, BAUD_RATE_115200}, + {B230400, BAUD_RATE_230400}, + {B460800, BAUD_RATE_460800}, + {B921600, BAUD_RATE_921600}, + {B2000000, BAUD_RATE_2000000}, + {B3000000, BAUD_RATE_3000000}, +}; + +static speed_t _get_speed(int baudrate) +{ + int index; + + for (index = 0; index < sizeof(_tbl)/sizeof(_tbl[0]); index ++) + { + if (_tbl[index].baudrate == baudrate) + return _tbl[index].speed; + } + + return B0; +} + +static int _get_baudrate(speed_t speed) +{ + int index; + + for (index = 0; index < sizeof(_tbl)/sizeof(_tbl[0]); index ++) + { + if (_tbl[index].speed == speed) + return _tbl[index].baudrate; + } + + return 0; +} + +static void _tc_flush(struct rt_serial_device *serial, int queue) +{ + rt_base_t level; + int ch = -1; + struct rt_serial_rx_fifo *rx_fifo = RT_NULL; + struct rt_device *device = RT_NULL; + + RT_ASSERT(serial != RT_NULL); + + device = &(serial->parent); + rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; + + switch(queue) + { + case TCIFLUSH: + case TCIOFLUSH: + RT_ASSERT(rx_fifo != RT_NULL); + + if((device->open_flag & RT_DEVICE_FLAG_INT_RX) || (device->open_flag & RT_DEVICE_FLAG_DMA_RX)) + { + RT_ASSERT(RT_NULL != rx_fifo); + level = rt_hw_interrupt_disable(); + rx_fifo->rx_cpt_index = 0; + rt_hw_interrupt_enable(level); + } + else + { + while (1) + { + ch = serial->ops->getc(serial); + if (ch == -1) break; + } + } + + break; + + case TCOFLUSH: + break; + } + +} +#endif /* RT_USING_POSIX_TERMIOS */ + /** * @brief Control the serial device. * @param dev The pointer of device driver structure @@ -1029,7 +1125,212 @@ static rt_err_t rt_serial_control(struct rt_device *dev, } break; +#ifdef RT_USING_POSIX_STDIO +#ifdef RT_USING_POSIX_TERMIOS + case TCGETA: + { + struct termios *tio = (struct termios*)args; + if (tio == RT_NULL) return -RT_EINVAL; + tio->c_iflag = 0; + tio->c_oflag = 0; + tio->c_lflag = 0; + + /* update oflag for console device */ + if (rt_console_get_device() == dev) + tio->c_oflag = OPOST | ONLCR; + + /* set cflag */ + tio->c_cflag = 0; + if (serial->config.data_bits == DATA_BITS_5) + tio->c_cflag = CS5; + else if (serial->config.data_bits == DATA_BITS_6) + tio->c_cflag = CS6; + else if (serial->config.data_bits == DATA_BITS_7) + tio->c_cflag = CS7; + else if (serial->config.data_bits == DATA_BITS_8) + tio->c_cflag = CS8; + + if (serial->config.stop_bits == STOP_BITS_2) + tio->c_cflag |= CSTOPB; + + if (serial->config.parity == PARITY_EVEN) + tio->c_cflag |= PARENB; + else if (serial->config.parity == PARITY_ODD) + tio->c_cflag |= (PARODD | PARENB); + + if (serial->config.flowcontrol == RT_SERIAL_FLOWCONTROL_CTSRTS) + tio->c_cflag |= CRTSCTS; + + cfsetospeed(tio, _get_speed(serial->config.baud_rate)); + } + break; + + case TCSETAW: + case TCSETAF: + case TCSETA: + { + int baudrate; + struct serial_configure config; + + struct termios *tio = (struct termios*)args; + if (tio == RT_NULL) return -RT_EINVAL; + + config = serial->config; + + baudrate = _get_baudrate(cfgetospeed(tio)); + config.baud_rate = baudrate; + + switch (tio->c_cflag & CSIZE) + { + case CS5: + config.data_bits = DATA_BITS_5; + break; + case CS6: + config.data_bits = DATA_BITS_6; + break; + case CS7: + config.data_bits = DATA_BITS_7; + break; + default: + config.data_bits = DATA_BITS_8; + break; + } + + if (tio->c_cflag & CSTOPB) config.stop_bits = STOP_BITS_2; + else config.stop_bits = STOP_BITS_1; + + if (tio->c_cflag & PARENB) + { + if (tio->c_cflag & PARODD) config.parity = PARITY_ODD; + else config.parity = PARITY_EVEN; + } + else config.parity = PARITY_NONE; + + if (tio->c_cflag & CRTSCTS) config.flowcontrol = RT_SERIAL_FLOWCONTROL_CTSRTS; + else config.flowcontrol = RT_SERIAL_FLOWCONTROL_NONE; + + /* set serial configure */ + serial->config = config; + serial->ops->configure(serial, &config); + } + break; + case TCFLSH: + { + int queue = (int)args; + + _tc_flush(serial, queue); + } + + break; + case TCXONC: + break; +#endif /*RT_USING_POSIX_TERMIOS*/ + case TIOCSWINSZ: + { + struct winsize* p_winsize; + + p_winsize = (struct winsize*)args; + rt_kprintf("\x1b[8;%d;%dt", p_winsize->ws_col, p_winsize->ws_row); + } + break; + case TIOCGWINSZ: + { + struct winsize* p_winsize; + p_winsize = (struct winsize*)args; + + if(rt_thread_self() != rt_thread_find("tshell")) + { + /* only can be used in tshell thread; otherwise, return default size */ + p_winsize->ws_col = 80; + p_winsize->ws_row = 24; + } + else + { + #include + #define _TIO_BUFLEN 20 + char _tio_buf[_TIO_BUFLEN]; + unsigned char cnt1, cnt2, cnt3, i; + char row_s[4], col_s[4]; + char *p; + + rt_memset(_tio_buf, 0, _TIO_BUFLEN); + + /* send the command to terminal for getting the window size of the terminal */ + rt_kprintf("\033[18t"); + + /* waiting for the response from the terminal */ + i = 0; + while(i < _TIO_BUFLEN) + { + _tio_buf[i] = finsh_getchar(); + if(_tio_buf[i] != 't') + { + i ++; + } + else + { + break; + } + } + if(i == _TIO_BUFLEN) + { + /* buffer overloaded, and return default size */ + p_winsize->ws_col = 80; + p_winsize->ws_row = 24; + break; + } + + /* interpreting data eg: "\033[8;1;15t" which means row is 1 and col is 15 (unit: size of ONE character) */ + rt_memset(row_s,0,4); + rt_memset(col_s,0,4); + cnt1 = 0; + while(_tio_buf[cnt1] != ';' && cnt1 < _TIO_BUFLEN) + { + cnt1++; + } + cnt2 = ++cnt1; + while(_tio_buf[cnt2] != ';' && cnt2 < _TIO_BUFLEN) + { + cnt2++; + } + p = row_s; + while(cnt1 < cnt2) + { + *p++ = _tio_buf[cnt1++]; + } + p = col_s; + cnt2++; + cnt3 = rt_strlen(_tio_buf) - 1; + while(cnt2 < cnt3) + { + *p++ = _tio_buf[cnt2++]; + } + + /* load the window size date */ + p_winsize->ws_col = atoi(col_s); + p_winsize->ws_row = atoi(row_s); + #undef _TIO_BUFLEN + } + + p_winsize->ws_xpixel = 0;/* unused */ + p_winsize->ws_ypixel = 0;/* unused */ + } + break; + case FIONREAD: + { + rt_size_t recved = 0; + rt_base_t level; + struct rt_serial_rx_fifo * rx_fifo = (struct rt_serial_rx_fifo *) serial->serial_rx; + + level = rt_hw_interrupt_disable(); + recved = rt_ringbuffer_data_len(&(rx_fifo->rb)); + rt_hw_interrupt_enable(level); + + *(rt_size_t *)args = recved; + } + break; +#endif /* RT_USING_POSIX_STDIO */ default : /* control device */ ret = serial->ops->control(serial, cmd, args);