Răsfoiți Sursa

完善 Serial V2 框架 (#5770)

* [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.
朱天龙 (Armink) 3 ani în urmă
părinte
comite
039efbb075

+ 13 - 1
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

+ 19 - 14
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;
 };
 
 /*

+ 301 - 0
components/drivers/serial/serial_v2.c

@@ -23,6 +23,10 @@
 #include <sys/ioctl.h>
 #include <dfs_file.h>
 
+#ifdef RT_USING_POSIX_TERMIOS
+#include <termios.h>
+#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 <shell.h>
+                    #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);