diff --git a/components/drivers/serial/dev_serial.c b/components/drivers/serial/dev_serial.c index 483f59f1e2b0..5517b470afec 100644 --- a/components/drivers/serial/dev_serial.c +++ b/components/drivers/serial/dev_serial.c @@ -39,6 +39,7 @@ #include #ifdef RT_USING_POSIX_STDIO +#include #include #include #include @@ -1339,12 +1340,16 @@ static rt_err_t rt_serial_control(struct rt_device *dev, } else config.parity = PARITY_NONE; - ret = serial->ops->configure(serial, &config); - if (ret != RT_EOK) + /* Software-only termios changes must not reset the UART FIFO. */ + if (rt_memcmp(&config, &serial->config, sizeof(config)) != 0) { - return ret; + ret = serial->ops->configure(serial, &config); + if (ret != RT_EOK) + { + return ret; + } + serial->config = config; } - serial->config = config; } break; #ifndef RT_USING_TTY @@ -1370,85 +1375,58 @@ static rt_err_t rt_serial_control(struct rt_device *dev, break; case TIOCGWINSZ: { - struct winsize* p_winsize; - p_winsize = (struct winsize*)args; - - if(rt_thread_self() != rt_thread_find("tshell")) + struct winsize *winsize = (struct winsize *)args; + char response[32] = { 0 }; + const char query[] = "\033[18t"; + rt_tick_t start_tick; + rt_size_t i = 0; + unsigned long rows, columns; + char *end; + + if (winsize == RT_NULL) { - /* only can be used in tshell thread; otherwise, return default size */ - p_winsize->ws_col = 80; - p_winsize->ws_row = 24; + ret = -RT_EINVAL; + break; } - 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); + rt_memset(winsize, 0, sizeof(*winsize)); + winsize->ws_row = 24; + winsize->ws_col = 80; + rt_device_write(dev, -1, query, sizeof(query) - 1); - /* 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) + start_tick = rt_tick_get(); + while (i < sizeof(response) - 1 && + rt_tick_get() - start_tick < rt_tick_from_millisecond(200)) + { + if (rt_device_read(dev, -1, &response[i], 1) == 1) { - _tio_buf[i] = finsh_getchar(); - if(_tio_buf[i] != 't') - { - i ++; - } - else + if (response[i++] == 't') { 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(cnt1 < _TIO_BUFLEN && _tio_buf[cnt1] != ';') - { - cnt1++; - } - cnt2 = ++cnt1; - while(cnt2 < _TIO_BUFLEN && _tio_buf[cnt2] != ';') - { - cnt2++; - } - p = row_s; - while(cnt1 < cnt2) - { - *p++ = _tio_buf[cnt1++]; - } - p = col_s; - cnt2++; - cnt3 = rt_strlen(_tio_buf) - 1; - while(cnt2 < cnt3) + else { - *p++ = _tio_buf[cnt2++]; + rt_thread_mdelay(1); } - - /* 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 */ + if (rt_memcmp(response, "\033[8;", 4) != 0) + { + break; + } + rows = strtoul(response + 4, &end, 10); + if (*end != ';') + { + break; + } + columns = strtoul(end + 1, &end, 10); + if (*end == 't' && end[1] == '\0' && + rows != 0 && rows <= 999 && columns != 0 && columns <= 999) + { + winsize->ws_row = rows; + winsize->ws_col = columns; + } } break; case FIONREAD: diff --git a/components/drivers/serial/dev_serial_v2.c b/components/drivers/serial/dev_serial_v2.c index fa5a68637349..7bdab8bad2c0 100644 --- a/components/drivers/serial/dev_serial_v2.c +++ b/components/drivers/serial/dev_serial_v2.c @@ -30,6 +30,7 @@ #endif /* RT_SERIAL_BUF_STRATEGY_DROP */ #ifdef RT_USING_POSIX_STDIO +#include #include #include #include @@ -1873,85 +1874,58 @@ static rt_err_t rt_serial_control(struct rt_device *dev, break; case TIOCGWINSZ: { - struct winsize *p_winsize; - p_winsize = (struct winsize *)args; - - if (rt_thread_self() != rt_thread_find(FINSH_THREAD_NAME)) + struct winsize *winsize = (struct winsize *)args; + char response[32] = { 0 }; + const char query[] = "\033[18t"; + rt_tick_t start_tick; + rt_size_t i = 0; + unsigned long rows, columns; + char *end; + + if (winsize == RT_NULL) { - /* only can be used in tshell thread; otherwise, return default size */ - p_winsize->ws_col = 80; - p_winsize->ws_row = 24; + ret = -RT_EINVAL; + break; } - 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"); + rt_memset(winsize, 0, sizeof(*winsize)); + winsize->ws_row = 24; + winsize->ws_col = 80; + rt_device_write(dev, -1, query, sizeof(query) - 1); - /* waiting for the response from the terminal */ - i = 0; - while (i < _TIO_BUFLEN) + start_tick = rt_tick_get(); + while (i < sizeof(response) - 1 && + rt_tick_get() - start_tick < rt_tick_from_millisecond(200)) + { + if (rt_device_read(dev, -1, &response[i], 1) == 1) { - _tio_buf[i] = finsh_getchar(); - if (_tio_buf[i] != 't') - { - i++; - } - else + if (response[i++] == 't') { 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 (cnt1 < _TIO_BUFLEN && _tio_buf[cnt1] != ';') - { - cnt1++; - } - cnt2 = ++cnt1; - while (cnt2 < _TIO_BUFLEN && _tio_buf[cnt2] != ';') - { - cnt2++; - } - p = row_s; - while (cnt1 < cnt2) - { - *p++ = _tio_buf[cnt1++]; - } - p = col_s; - cnt2++; - cnt3 = rt_strlen(_tio_buf) - 1; - while (cnt2 < cnt3) + else { - *p++ = _tio_buf[cnt2++]; + rt_thread_mdelay(1); } - - /* 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 */ + if (rt_memcmp(response, "\033[8;", 4) != 0) + { + break; + } + rows = strtoul(response + 4, &end, 10); + if (*end != ';') + { + break; + } + columns = strtoul(end + 1, &end, 10); + if (*end == 't' && end[1] == '\0' && + rows != 0 && rows <= 999 && columns != 0 && columns <= 999) + { + winsize->ws_row = rows; + winsize->ws_col = columns; + } } break; case FIONREAD: diff --git a/components/drivers/serial/serial_tty.c b/components/drivers/serial/serial_tty.c index aa8054876d43..d505c7310064 100644 --- a/components/drivers/serial/serial_tty.c +++ b/components/drivers/serial/serial_tty.c @@ -17,6 +17,8 @@ #include #include +#include + #define TTY_NAME_PREFIX "S" /* (S)erial */ #define LWP_TTY_WORKQUEUE_PRIORITY 3 @@ -159,6 +161,19 @@ static void _serial_tty_set_speed(struct lwp_tty *tp) tp->t_termios_init_in.__c_ispeed = tp->t_termios_init_in.__c_ospeed = cfgetospeed(&tp->t_termios_init_in); } +static void _serial_tty_update_winsize(struct lwp_tty *tp, + struct rt_serial_device *serial) +{ + struct winsize winsz; + + rt_memset(&winsz, 0, sizeof(winsz)); + if (rt_device_control(&serial->parent, TIOCGWINSZ, &winsz) == RT_EOK && + winsz.ws_row != 0 && winsz.ws_col != 0) + { + tp->t_winsize = winsz; + } +} + static int _serial_isbusy(struct rt_serial_device *serial) { rt_thread_t user_thread = rt_console_current_user(); @@ -222,6 +237,13 @@ static int serial_tty_open(struct lwp_tty *tp) * to avoid driver accesssing null data, * these are setup only after tty is registered */ + if (rt_console_get_device() == &serial->parent) + { + /* Query before the bypass is installed so the response stays in + * the raw serial receive queue instead of being delivered as + * input. */ + _serial_tty_update_winsize(tp, serial); + } _setup_serial(serial, tp, softc); } return error; @@ -243,20 +265,8 @@ static void serial_tty_close(struct lwp_tty *tp) static int serial_tty_ioctl(struct lwp_tty *tp, rt_ubase_t cmd, rt_caddr_t data, struct rt_thread *td) { - int error; - switch (cmd) - { - default: - /** - * Note: for the most case, we don't let serial layer handle ioctl, - * for that they can't act properly regarding to the process - * management system, since it is unawared of that. So a ENOSYS is - * returned and caused the TTY layer to handle ioctl itself. - */ - error = -ENOSYS; - break; - } - return error; + /* Let the TTY layer handle process state and cached terminal settings. */ + return -ENOSYS; } static int serial_tty_param(struct lwp_tty *tp, struct termios *t)