简体   繁体   English

Linux串行读取块minicom

[英]Linux serial read blocks minicom

I'm attempting to read from a serial port ( /dev/ttyS4 ) on a BeagleBone Black, but I think(?) this should apply to all Linux devices in general. 我正在尝试从BeagleBone Black上的串行端口( /dev/ttyS4 )进行读取,但是我认为这通常适用于所有Linux设备。

Currently, I can set up minicom with a baud rate of 9600 and 8N1 data to read from the serial port correctly. 目前,我可以设置波特率为9600和8N1数据的minicom ,以正确地从串行端口读取数据。 However, if I attempt to directly cat /dev/ttyS4 , nothing shows up in my terminal. 但是,如果我尝试直接显示cat /dev/ttyS4 ,则终端中没有任何显示。 My code also does this, and returns a Resource temporarily unavailable error, which I suspect is what is happening with the cat command. 我的代码也执行此操作,并返回Resource temporarily unavailable错误,我怀疑这是cat命令所发生的事情。

If I run stty -F /dev/ttyS4 , I get the following output (which, as far as I can tell, is consistent with my minicom settings): 如果运行stty -F /dev/ttyS4stty -F /dev/ttyS4得到以下输出(据我所知,这与我的minicom设置一致):

speed 9600 baud; line = 0;
intr = <undef>; quit = <undef>; erase = <undef>; kill = <undef>; eof = <undef>; start = <undef>; stop = <undef>; susp = <undef>; rprnt = <undef>; werase = <undef>; lnext = <undef>; flush = <undef>;
-brkint -imaxbel
-opost -onclr
-isig -iexten -echo -echoe -echok -echoctl -echoke

An interesting note is that when I have minicom open, if I start my program, minicom will stop printing anything, and stay that way even if I stop my program. 有趣的是,当我打开minicom ,如果我启动程序,minicom将停止打印任何内容,并且即使我停止程序也将保持这种状态。 I need to open the serial settings again ( Ctrl-A , P ) and close it for minicom to resume working (it appears that nothing was changed). 我需要再次打开串行设置( Ctrl-AP )并关闭它以使minicom恢复工作(似乎没有任何更改)。

My code is as follows: 我的代码如下:

int main() {
    std::cout << "Starting..." << std::endl;

    std::cout << "Connecting..." << std::endl;
    int tty4 = open("/dev/ttyS4", O_RDWR | O_NOCTTY | O_NDELAY);
    if (tty4 < 0) {
        std::cout << "Error opening serial terminal." << std::endl;
    }

    std::cout << "Configuring..." << std::endl;
    struct termios oldtio, newtio;
    tcgetattr(tty4, &oldtio);   // save current serial port settings
    bzero(&newtio, sizeof(newtio)); // clear struct for new settings

    newtio.c_cflag = B9600 | CS8 | CREAD | CLOCAL;
    newtio.c_iflag = IGNPAR | ICRNL;
    newtio.c_oflag = 0;
    newtio.c_lflag = ICANON;

    tcflush(tty4, TCIFLUSH);
    tcsetattr(tty4, TCSANOW, &newtio);

    std::cout << "Reading..." << std::endl;
    while (true) {
        uint8_t byte;
        int status = read(tty4, &byte, 1);
        if (status > 0) {
            std::cout << (char)byte;
        } else if (status == -1) {
            std::cout << "\tERROR: " << strerror(errno) << std::endl;
        }
    }

    tcsetattr(tty4, TCSANOW, &oldtio);
    close(tty4);
}

Edit: I've gotten the serial port to work correctly (in python) by following Adafruit's tutorial for using python with the BeagleBone. 编辑:通过遵循Adafruit的BeagleBone使用python教程,我已经使串行端口正常工作(在python中)。 At this point I'm certain that I'm doing something wrong; 在这一点上,我敢肯定, 我做错了什么; the question is what. 问题是什么。 I would much prefer using C++ over python, so it'd be great to get that working. 我会更喜欢使用C ++而不是python,因此能够正常工作将非常棒。

Your program opens the serial terminal in nonblocking mode. 您的程序以非阻塞模式打开串行终端。

  int tty4 = open("/dev/ttyS4", O_RDWR | O_NOCTTY | O_NDELAY); 

Nonblocking I/O, especially read operations, requires additional, special handling in a program. 非阻塞I / O,特别是读取操作,需要在程序中进行其他特殊处理。 Since you neglect to mention this mode, and your program has no capability to properly process this mode, this could be considered a bug. 由于您忽略了此模式,并且您的程序无法正确处理此模式,因此可以将其视为错误。

Either remove O_NDELAY option from the open() call, or insert a fcntl(tty4, F_SETFL, 0) statement to revert back to blocking mode. open()调用中删除O_NDELAY选项,或插入fcntl(tty4, F_SETFL, 0)语句以恢复为阻塞模式。


My code also does this, and returns a Resource temporarily unavailable error, 我的代码也这样做,并返回Resource temporarily unavailable错误,

That's an EAGAIN error, which is consistent with a nonblocking read() . 这是一个EAGAIN错误,与无阻塞read()一致。
The man page describes this error will occur when "the file descriptor ... has been marked nonblocking (O_NONBLOCK), and the read would block". 手册页描述了当“文件描述符...被标记为非阻塞(O_NONBLOCK),并且读取将阻塞”时,将发生此错误。
The read() syscall "would block" because there is no data to satisfy the read request. read()系统调用将“阻塞”,因为没有数据可以满足读取请求。

If you insist on using nonblocking mode, then your program must be able to cope with this condition, which is not an error but a temporary/transient status. 如果您坚持使用非阻塞模式,则您的程序必须能够应付这种情况,这不是错误,而是临时/临时状态。
But blocking mode is the simpler and preferred mode of operation for typical programs in a multitasking system. 但是对于多任务系统中的典型程序,阻塞模式是更简单,更可取的操作模式。
Your program should be modified as previously mentioned. 您的程序应如前所述进行修改。


There are numerous issues with the initialization of the serial terminal. 串行终端的初始化存在许多问题。


  tcgetattr(tty4, &oldtio); // save current serial port settings 

The return values from the tcgetattr() and tcsetattr() syscalls are never checked for errors. 永远不会检查tcgetattr()tcsetattr()系统调用的返回值是否有错误。


  bzero(&newtio, sizeof(newtio)); // clear struct for new settings 

Starting with an empty termios structure is almost always a bad idea. 从一个空的termios结构开始几乎总是一个坏主意。 It may appear to work on some systems, but it is not portable code. 它可能在某些系统上似乎可以运行,但是它不是可移植的代码。
The proper method for initializing a termios structure is to use values from tcgetattr() . 初始化termios结构的正确方法是使用tcgetattr()的值。
See Setting Terminal Modes Properly . 请参阅正确设置终端模式
Since it is already called, all you need is newtio = oldtio to copy the structure. 由于已经调用了它,因此您只需复制newtio = oldtio即可复制该结构。


  newtio.c_cflag = B9600 | CS8 | CREAD | CLOCAL; newtio.c_iflag = IGNPAR | ICRNL; newtio.c_oflag = 0; newtio.c_lflag = ICANON; 

Rather than assignment of constants, the proper method of changing these flags is to enable or disable the individual attributes. 更改常量的正确方法不是启用常量,而是启用或禁用各个属性。
The following should suffice for canonical mode: 对于规范模式,以下内容就足够了:

    newtio.c_cflag |= CLOCAL | CREAD;
    newtio.c_cflag &= ~CSIZE;
    newtio.c_cflag |= CS8;         /* 8-bit characters */
    newtio.c_cflag &= ~PARENB;     /* no parity bit */
    newtio.c_cflag &= ~CSTOPB;     /* only need 1 stop bit */
    newtio.c_cflag &= ~CRTSCTS;    /* no hardware flowcontrol */

    newtio.c_lflag |= ICANON | ISIG;  /* canonical input */
    newtio.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN);

    newtio.c_iflag &= ~INPCK;
    newtio.c_iflag |= ICRNL;
    newtio.c_iflag &= ~(INLCR | IGNCR | IUCLC | IMAXBEL);
    newtio.c_iflag &= ~(IXON | IXOFF | IXANY);   /* no SW flowcontrol */

    newtio.c_oflag &= ~OPOST;

The following is the preferred method for setting the baudrate: 以下是设置波特率的首选方法:

    cfsetospeed(&newtio, B9600);
    cfsetispeed(&newtio, B9600);

If any salient attributes are left unspecified, the existing settings are used. 如果未指定任何显着属性,则使用现有设置。
This can lead to erratic program behavior, eg sometimes it works, sometimes it doesn't. 这可能导致程序行为不稳定,例如,有时它起作用,有时却不起作用。


An interesting note is that when I have minicom open, if I start my program, minicom will stop printing anything, and stay that way even if I stop my program. 有趣的是,当我打开minicom时,如果我启动程序,minicom将停止打印任何内容,并且即使我停止程序也将保持这种状态。 I need to open the serial settings again (Ctrl-A, P) and close it for minicom to resume working (it appears that nothing was changed). 我需要再次打开串行设置(Ctrl-A,P),然后关闭它以使minicom恢复工作(似乎没有任何更改)。

The serial terminal is not intended for sharing among more than one process. 串行终端不能在多个进程之间共享。
Some of the termios attributes have to be implemented in the serial device driver, which has no concept of sharing the port. 一些termios属性必须在没有共享端口概念的串行设备驱动程序中实现。 The most recent termios attributes are in effect for the device. 最新的termios属性对设备有效。
When you execute your program after minicom has started, you are clobbering the termios attributes that minicom expects to execute with. minicom启动之后执行程序时,您正在破坏minicom期望与之一起执行的termios属性。
You are restoring the termios attributes to minicom 's requirements by using its menu. 您正在通过使用其菜单将termios属性还原为minicom的要求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM