终端提示失真且不可读

时间:2013-05-14 20:01:04

标签: terminal uart termios

我是linux编程的新手。我按照Web上的示例来读/写控制台,例如“/ dev / ttyS0”。每次运行代码时,它都会退出而不会提示用户写入输入。它也会扭曲终端提示符(换行符),我无法看到我正在输入的内容......这是我正在使用的代码:

int main(int argc, char** argv)
{
  struct termios tio;
  struct termios stdio;
  int tty_fd;
  /* fd_set rdset; */

  printf("Please start with %s /dev/ttyS0 (for example)\n",argv[0]);
  unsigned char mesg='D';

  memset(&stdio,0,sizeof(stdio));
  stdio.c_iflag=0;
  stdio.c_oflag=0;
  stdio.c_cflag=0;
  stdio.c_lflag=0;
  stdio.c_cc[VMIN]=1;
  stdio.c_cc[VTIME]=0;
  tcsetattr(STDOUT_FILENO,TCSANOW,&stdio);
  tcsetattr(STDOUT_FILENO,TCSAFLUSH,&stdio);
  fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);       // make the reads non-blocking

  memset(&tio,0,sizeof(tio));
  tio.c_iflag=0;
  tio.c_oflag=0;
  tio.c_cflag=CS8|CREAD|CLOCAL;           // 8n1, see termios.h for more information
  tio.c_lflag=0;
  tio.c_cc[VMIN]=1;
  tio.c_cc[VTIME]=5;

  tty_fd=open(argv[1], O_RDWR | O_NONBLOCK | O_NOCTTY);
  cfsetospeed(&tio,B115200);            // 115200 baud
  cfsetispeed(&tio,B115200);            // 115200 baud

  tcsetattr(tty_fd,TCSANOW,&tio);
  while (mesg != 'q') {
    if (read(tty_fd,&mesg,1)>0)        write(STDOUT_FILENO,&mesg,1);              // if new data is available on the serial port, print it out
    if (read(STDIN_FILENO,&mesg,1)>0)  write(tty_fd,&mesg,1);                     // if new data is available on the console, send it to the serial port
  }

  close(tty_fd);

  return(0);
}

1 个答案:

答案 0 :(得分:1)

当您尝试更改tty参数的代码时,您应该使用保存和恢复参数的脚本包装测试程序的调用,以防程序忽略这样做。

这可以这样做:

 $ SAVED_TTY=$(stty -g)          # save the good settings once
 $ ./a.out ; stty $SAVED_TTY     # restore than after each run of the program

-g的{​​{1}}选项使其将所有tty设置“pickled”输出到字符串中,这可以作为将来stty调用的参数恢复相同的设置。

(正确编写的tty操作程序在退出时会注意恢复终端设置,即使它们通过接收任何可以处理的致命信号而突然退出。)

至于如何循环回写入tty设备的内容的问题,tty子系统本身没有这方面的一般功能。标准的tty线路规则模块可以将传入的字符回显给输出,这样当用户使用面向行的程序时,他们可以看到自己的输入,但是没有软件环回,因此tty设备假装接收到它有的一些字符刚送过。

然而,某些串行硬件能够进行硬件环回:基本上将UART TX线连接到RX线以进行测试。

Linux tty支持调制解调器控制ioctl,如果硬件支持,它可用于打开和关闭它。这采用sttyTIOCMGET ioctls的形式。这些ioctl使用的值是各种掩码的逻辑或,其中一个是TIOCMSET

所以,我认为设置硬件环回会是这样的:

TIOCM_LOOP

如果要求设置unsigned int modem_control_bits; result = ioctl(tty_descriptor, TIOCMGET, &modem_control_bits); /* check result for error, of course */ modem_control_bits |= TIOCM_LOOP; /* request loopback from serial port */ result = ioctl(tty_descriptor, TIOCMSET, &modem_control_bits); /* check result for error */ ,但是硬件不支持,则每个串行驱动程序是否会报告错误尚不清楚。 (我不认为只是因为结果为零,它必然有效)。

还有其他TIOCM_LOOP位,因此您可以执行标准操作,例如打开和关闭DTR,或检测指示灯是否亮起等等。