Find the answer to your Linux question:
Results 1 to 7 of 7
I've searched all over, but can't seem to find this one. I have a program (C++) where I'm reading and writing to the serial port. Everything works fine until I ...
Enjoy an ad free experience by logging in. Not a member yet? Register.
  1. #1
    Just Joined!
    Join Date
    Dec 2010
    Posts
    6

    Serial Port help


    I've searched all over, but can't seem to find this one.

    I have a program (C++) where I'm reading and writing to the serial port. Everything works fine until I try to send a message larger than the driver's buffer (around 4k I think). After the buffer gets full, the write() call blocks which stops my read/write thread cold, losing receive data.

    I'd like to be able to write say, 200 bytes of data to the port, then wait until the buffer is below 100 before putting another 200 bytes in. My messages can be in the 64k range, so I'm well above the 1 page buffer provided.

    I'd also like a non-blocking way of knowing when all the data has been sent. I could easily poll to see what's in the buffer in my thread.

    So, what I really need is a way to query the transmit buffer to see what's left to go out. I haven't been able to figure this out. A call similar to:
    ioctl(fd, FIONREAD, &bytes)
    would be perfect. That call works great for checking the input buffer.

    Any thoughts?

  2. #2
    Just Joined!
    Join Date
    Dec 2010
    Posts
    6
    For completeness, I found a workable solution.
    ioctl(fd, TIOCOUTQ, &bytes)
    gives the desired results, on Linux anyway.

    It doesn't work on Solaris though, which seems strange to me since it is supposed to be a POSIX function. I get no error on Solaris, it just doesn't ever return anything but 0.

  3. #3
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,753
    Quote Originally Posted by brianc1969 View Post
    For completeness, I found a workable solution.
    ioctl(fd, TIOCOUTQ, &bytes)
    gives the desired results, on Linux anyway.

    It doesn't work on Solaris though, which seems strange to me since it is supposed to be a POSIX function. I get no error on Solaris, it just doesn't ever return anything but 0.
    Ioctl calls are notoriously platform and OS version specific. Avoid them if at all possible if you plan on making your software run on more than one target OS. If you are trying to read and write to the same serial port at the same time, then you REALLY should be using select() to know when the port is capable of taking more data on output, and to tell you when there is data to read. You probably want to configure your file descriptor with the O_NONBLOCK flag set on open. Then, when you write to the device file descriptor, you can see how many bytes it took and determine where to start from when select() informs you again that it is ready for more data. Just an observation, but you are pretty new to this on Linux/Unix?
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

  4. $spacer_open
    $spacer_close
  5. #4
    Just Joined!
    Join Date
    Dec 2010
    Posts
    6
    Quote Originally Posted by Rubberman View Post
    Ioctl calls are notoriously platform and OS version specific. Avoid them if at all possible if you plan on making your software run on more than one target OS. If you are trying to read and write to the same serial port at the same time, then you REALLY should be using select() to know when the port is capable of taking more data on output, and to tell you when there is data to read. You probably want to configure your file descriptor with the O_NONBLOCK flag set on open. Then, when you write to the device file descriptor, you can see how many bytes it took and determine where to start from when select() informs you again that it is ready for more data. Just an observation, but you are pretty new to this on Linux/Unix?
    I'm pretty new to controlling the serial port in general.

    What I don't understand though, if I use select, how do I know when all data has been transmitted instead of just accepted into the transmit buffer? Part of this is that I have to lower the RTS signal once all data is transmitted. That means out on the wire, not just loaded into the buffer.
    Using the ioctl, I can tell when the buffer is completely empty, not just when it's able to take more data.
    Is there something I'm missing with the select call?

  6. #5
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,753
    Quote Originally Posted by brianc1969 View Post
    I'm pretty new to controlling the serial port in general.

    What I don't understand though, if I use select, how do I know when all data has been transmitted instead of just accepted into the transmit buffer? Part of this is that I have to lower the RTS signal once all data is transmitted. That means out on the wire, not just loaded into the buffer.
    Using the ioctl, I can tell when the buffer is completely empty, not just when it's able to take more data.
    Is there something I'm missing with the select call?
    Why do you have to lower the RTS signal yourself? Are you writing a device driver? Assuming you have configured the port correctly, such as enabling hardware handshaking/flow-control, then the system driver will happily take care of all that cruft for you. The only time I needed to deal with things at that level was back in the dark ages when I was writing device drivers...
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

  7. #6
    Just Joined!
    Join Date
    Dec 2010
    Posts
    6
    Quote Originally Posted by Rubberman View Post
    Why do you have to lower the RTS signal yourself? Are you writing a device driver? Assuming you have configured the port correctly, such as enabling hardware handshaking/flow-control, then the system driver will happily take care of all that cruft for you. The only time I needed to deal with things at that level was back in the dark ages when I was writing device drivers...
    So what you're saying is that the driver handles that for me if I've enabled hardware flow control? Guess I'm too much of a control freak! When I get back to work on Monday, I'll have to check that out and re-think my logic with select and see what all happens.

    Should I not even use threads for each serial port then? Just use select in the main thread?

  8. #7
    Linux Guru Rubberman's Avatar
    Join Date
    Apr 2009
    Location
    I can be found either 40 miles west of Chicago, in Chicago, or in a galaxy far, far away.
    Posts
    11,753
    Quote Originally Posted by brianc1969 View Post
    So what you're saying is that the driver handles that for me if I've enabled hardware flow control? Guess I'm too much of a control freak! When I get back to work on Monday, I'll have to check that out and re-think my logic with select and see what all happens.

    Should I not even use threads for each serial port then? Just use select in the main thread?
    Threads are for where you need to be doing more than one thing at a time, such as handling I/O from multiple ports with different processing needs. If all you are doing is reading/writing, then perhaps not. However, if you need to be able to do both input and output simultaneously, then use threads, otherwise, check for fd sets from select, and handle exceptions, input, and then output in that order.
    Sometimes, real fast is almost as good as real time.
    Just remember, Semper Gumbi - always be flexible!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •