Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 48 additions & 70 deletions components/drivers/serial/dev_serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <rtdbg.h>

#ifdef RT_USING_POSIX_STDIO
#include <stdlib.h>
#include <dfs_file.h>
#include <fcntl.h>
#include <unistd.h>
Expand Down Expand Up @@ -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
Expand All @@ -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 <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);
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_delta(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:
Expand Down
119 changes: 55 additions & 64 deletions components/drivers/serial/dev_serial_v2.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#endif /* RT_SERIAL_BUF_STRATEGY_DROP */

#ifdef RT_USING_POSIX_STDIO
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
Expand Down Expand Up @@ -1873,85 +1874,75 @@ 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;
rt_int32_t old_rx_timeout;
rt_int32_t no_wait_timeout = RT_WAITING_NO;
rt_bool_t rx_timeout_changed = RT_FALSE;

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 <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);
rt_memset(winsize, 0, sizeof(*winsize));
winsize->ws_row = 24;
winsize->ws_col = 80;

/* send the command to terminal for getting the window size of the terminal */
rt_kprintf("\033[18t");
/* A blocking serial read waits forever if the terminal does not
* answer; make the query non-blocking for its duration. */
if (rt_device_control(dev, RT_SERIAL_CTRL_GET_RX_TIMEOUT, &old_rx_timeout) == RT_EOK &&
rt_device_control(dev, RT_SERIAL_CTRL_SET_RX_TIMEOUT, &no_wait_timeout) == RT_EOK)
{
rx_timeout_changed = RT_TRUE;
}

/* waiting for the response from the terminal */
i = 0;
while (i < _TIO_BUFLEN)
rt_device_write(dev, -1, query, sizeof(query) - 1);

start_tick = rt_tick_get();
while (i < sizeof(response) - 1 &&
rt_tick_get_delta(start_tick) < rt_tick_from_millisecond(200))
{
if (rt_device_read(dev, -1, &response[i], 1) == 1)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是否需要判断之前是否设置过O_NONBLOCK,v2默认read是永久等待

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已处理,commit cd8ac61。

  • v1 的 _serial_poll_rx() 本身是非阻塞的,问题只在 v2:RT_SERIAL_RX_BLOCKING 下 rx_timeout 默认是 RT_WAITING_FOREVER,单次 rt_device_read() 可能永久阻塞,而 200 ms 的 tick 检查只在两次 read 之间生效。
  • 现在查询期间通过 RT_SERIAL_CTRL_GET_RX_TIMEOUT / RT_SERIAL_CTRL_SET_RX_TIMEOUT 保存并切到 RT_WAITING_NO,循环结束后恢复原值;poll 模式(rx_bufsz == 0)下这两个命令返回 -RT_EPERM,保持原有的非阻塞行为。
  • 没有直接判断 O_NONBLOCK:这里是直接操作 device,而不是 fd,O_NONBLOCK 属于 fd 层状态;保存/恢复设备层 rx_timeout 更直接,也不会重新配置 UART。

{
_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
if (rx_timeout_changed)
{
rt_device_control(dev, RT_SERIAL_CTRL_SET_RX_TIMEOUT, &old_rx_timeout);
}

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:
Expand Down
38 changes: 24 additions & 14 deletions components/drivers/serial/serial_tty.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include <rtdevice.h>
#include <terminal/terminal.h>

#include <sys/ioctl.h>

#define TTY_NAME_PREFIX "S" /* (S)erial */
#define LWP_TTY_WORKQUEUE_PRIORITY 3

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand Down
Loading