Correct initialization sequence for Linux serial p

2019-06-19 14:38发布

问题:

I wrote an application that must use serial ports on Linux, especially ttyUSB ones. Reading and writing operations are performed with standard select()/read() loop and write(), and there is probably nothing wrong in them, but initialization code (or absence of some part of it) damages something in the tty subsystem. Here it is:


  vuxboot(string filename, unsigned baud = B115200) : _debug(false) {
    _fd = open(filename.c_str(), O_RDWR | O_NOCTTY);
    if(_fd < 0) throw new io_error("cannot open port");

    // Serial initialization was written with FTDI USB-to-serial converters
    // in mind. Anyway, who wants to use non-8n1 protocol?

    tcgetattr(_fd, &_termios);

    termios tio = {0};
    tio.c_iflag = IGNPAR;
    tio.c_oflag = 0;
    tio.c_cflag = baud | CLOCAL | CREAD | CS8;
    tio.c_lflag = 0;

    tcflush(_fd, TCIFLUSH);
    tcsetattr(_fd, TCSANOW, &tio);
  }

Another tcsetattr(_fd, TCSANOW, &_termios) sits in the destructor, but it is irrelevant.

With or without this termios initialization, strange things happen in system after the application exits. Sometimes plain cat (or hd) exits immediately printing nothing or same stuff each time, sometimes it is waiting and not displaying any of the data that is surely sent onto the port; and close() (read() too, but not every time) emits a strange WARNING to dmesg referring to usb-serial.c.

I checked the hardware and firmware tens of times (even on different machines) and I am sure it is working as intended; moreover, I stripped the firmware to just print same message over and over.

How can I use serial port without destroying anything? Thanks.

回答1:

Hitting a WARN_ON line might mean that you've hit a kernel bug. I know that there has been much work on improving the USB-serial driver lately; I suggest trying a newer kernel, and/or asking on the linux-usb@vger.kernel.org mailing list.



回答2:

I am not sure what is wrong with your snippet of code there but this might come in handy, if you haven't already seen it: Serial Programming Guide for POSIX Operating Systems

I had to do some serial port interfacing quite recently and this library worked fine, that might serve as another example.



回答3:

Just as a side note really, your error check on open isn't quite right - error conditions are signalled by a return value of -1. (0 is a perfectly valid fd, usually connected to stdin.)



回答4:

You might want to try:

  vuxboot(string filename, unsigned baud = B115200) : _debug(false) {
    _fd = open(filename.c_str(), O_RDWR | O_NOCTTY);
    if(_fd < 0) throw new io_error("cannot open port");

    // Serial initialization was written with FTDI USB-to-serial converters
    // in mind. Anyway, who wants to use non-8n1 protocol?

    tcgetattr(_fd, &_termios);

-   termios tio;
+   termios tio;
+   memcpy(&tio, &_termios, sizeof(struct termios)); 

    tio.c_iflag = IGNPAR;
    tio.c_oflag = 0;
    tio.c_cflag = baud | CLOCAL | CREAD | CS8;
    tio.c_lflag = 0;

    tcflush(_fd, TCIFLUSH);
    tcsetattr(_fd, TCSANOW, &tio);
}

This makes it so that any unexpected fields of termios on your system get somewhat reasonable values.



回答5:

Okay. This may not be a perfect solution... it definitely isn't. I just threw out FT232 converter (fried it, actually), and used CP2102-based one. It just works now (and also is 6 times cheaper).