Thread: Using cat with a serial port on Linux

  1. #1
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413

    Using cat with a serial port on Linux

    I think I must have a fundamental misunderstanding of things here. Short story, trying to connect two serial devices and make them talk. For now, those devices are: (1) linux computer and (2) windows computer using python/pyserial.

    I can run "echo 'a' > /dev/ttyUSB0" on (1) and receive it just fine on (2). The problem is receiving data on (1). The ultimate goal here is to continuously log the data coming into the serial port on (1).

    So here's the misunderstanding part: I've read in multiple places that I should be able to type "cat /dev/ttyUSB0 > file.txt" to log the serial data. I would think that would continuously read/write whatever data comes into the serial port. That is not the case, at least here. What's happening is that I'll run cat as shown above on (1), and type/write things on (2) and I get nothing. I do however get what I sent over, or part of it, if I run cat a 2nd time.

    What is actually supposed to happen? Is it supposed to continuously take characters from the serial port and store them to file.txt, or is it supposed to basically flush the input buffer once like I'm actually seeing? Any clues to what's going on here?

    P.S. I've matched baud rates, flow control, etc. and switched the port to raw on (1) via "stty -F /dev/ttyUSB0 raw"

  2. #2
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    O_o

    Depending on stuff, the other layers may be buffering until newline/eof bytes.

    Try the redirection using "dd" operating on a single byte for each operation.

    Soma
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  3. #3
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    (This should probably be moved to the Linux forum, BTW.)

    Are you using a null modem cable? You need to, between two computers.

    If you are, you most likely have a crappy USB-serial dongle on one end; one that does not actually wire one of the handshake lines (RTS/CTS, DTR/DSR). (The very common FTDI chips definitely do support all of those just fine, and even in some of the weird combinations (RTS/CTS+DTR/DSR, with XON/XOFF flow control, is the weirdest one I've heard used). I've heard some dongle makers just do not bother soldering all the lines..)

    Also, Linux serial ports usually default to -crtscts; i.e. RTS/CTS-handshaking disabled. (stty raw mostly sets the local serial end stuff, not handshaking defaults; you probably want to explicitly specify the handshaking method you wish to use. Run stty -F /dev/ttyUSB0 -a to see all the settings.)
    In other words, the Windows end might be using RTS/CTS to indicate it wants to send, but the Linux end is waiting for a change on the DTR/DSR lines. So do check you actually use the same handshaking on both ends.

  4. #4
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413
    I'll try dd tomorrow.

    Forgot to mention that the computers are connected via USB to 2-wire RS485 adapters, so as far as wiring goes, it's just a matter of matching polarities.

    Should've added to the original post that I've tried:
    - Enabling/disabling multiple combinations of the flow control (xonxoff, rts/cts, etc.), which actually should be disabled since it's 2-wire
    - changing EOL characters on (1) end via stty
    - sending CR/LFs from (2)
    - different USB RS485 adapters, I have quite a few

    It's just the damnedest thing because comms from (1) to (2) work perfectly fine (using echo at prompt on (1) and PuTTY on (2)). Like I said, characters do eventually get through from (2) to (1) if I re-run cat after the characters have been sent (and also /dev/ttyUSB0 is set to raw via stty), which leads me to believe that I'm missing something about how this is supposed to work.

  5. #5
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413
    I think tomorrow I'll get out some RS232 adapters and hook the two comps up via a DB9 null modem cable and see if I have the same problem as well, minding the flow control of course.

  6. #6
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by Epy View Post
    Forgot to mention that the computers are connected via USB to 2-wire RS485 adapters, so as far as wiring goes, it's just a matter of matching polarities.
    Have you checked if connecting both dongles to the Linux machine still exhibits the same problem? Should be trivial to check, assuming you have a short RS485 cable handy. If you only have one free USB on the Linux machine, use a powered USB hub.

    Have you checked (with an oscilloscope or similar) when the RS485 data is actually sent?

    Quote Originally Posted by Epy View Post
    - Enabling/disabling multiple combinations of the flow control (xonxoff, rts/cts, etc.), which actually should be disabled since it's 2-wire
    Yeah, but did you check? The Linux TTY interface has a really "funny" wrinkle in that if at least one of the settings were applied successfully, the functions return success. So, if you encounter any problems with the tty, you need to check (using stty -a or otherwise) what the actual applied settings were.

    Quote Originally Posted by Epy View Post
    Like I said, characters do eventually get through from (2) to (1) if I re-run cat after the characters have been sent (and also /dev/ttyUSB0 is set to raw via stty), which leads me to believe that I'm missing something about how this is supposed to work.
    It could really be as simple as using stty -F /dev/ttyUSB0 raw ixany on both sides. Perhaps both sides are set up so that both wait for the other to send first, and closing then reopening the Linux side gives the Windows side the go-ahead it needs?

    Personally, I'd grab my favourite sub-$20 microcontroller with a native USB interface (most Arduinos have a serial-to-USB chip, not native USB), a $1 MAX485 chip (and a 150-ohm resistor), and wire it on a breadboard to replace one of the USB-RS485 dongles, so I could test and see exactly what is happening on the hardware level. (Mine has a nice LED I can turn on when it receives the first byte, for example.) The native USB interface allows bypassing the tty layer altogether on one side, so you can see exactly what is happening on the hardware level. But if I had an oscilloscope, I'd use that instead.

  7. #7
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413
    Since I'm doing everything through SSH, I used/checked with stty. I'll also try both dongles on the linux machine as well.

  8. #8
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413
    Not having any luck here, beginning to think it's something with OpenWrt. I've tried so many different adapters with all kinds of settings, all suggestions, and getting nowhere. I actually had the most luck with the RS485 adapters.

  9. #9
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    With a two-wire RS-485, the wires are really kind-of tri-state. Most USB RS-485 dongles use RTS to indicate the local end wishes to send, and absense of RTS to indicate the local end is willing to receive. (That is, RTS enables the output tristates, and no-RTS disables them. The RTS here is not a separate signal line, just a logical state/flag the USB dongle has, and the kernel serial driver controls.)

    This matches the Windows serial driver behaviour, but it does not have a equivalent TTY control setting in POSIX ("RTS toggle on send"). Linux does, via TIOCSRS485 ioctl() on the open device descriptor. Unfortunately, standard stty does not have that, and I don't see it implemented in the USB-serial drivers, either.

    You can do this in software, by manipulating the terminal settings (for ttyUSB0), and using tcdrain() to wait for buffers to be sent to the device. (Some additional timeouts should be added, to account for device buffering; I think this is the key reason it's not implemented in Linux drivers.) It should be quite simple and robust C program, that can incorporate stty and cat, without any extra libraries.

    If you just want to set up the Linux end to receive data, try
    Code:
    stty -F /dev/ttyUSB0 raw crtscts min 1 time 0
    bash -c 'exec 3>/dev/ttyUSB0 ; sleep .1 ; exec 3>&-'
    cat /dev/ttyUSB0 > file
    The bash command opens the device write-only; this should enable RTS. However, after 0.1 seconds, the device is explicitly closed, without anything actually being sent. Next, the device is opened in read-only mode, which should NOT enable RTS (only CTS, which the RS-485 USB dongles should ignore).

    The reason you wish to flag RTS for a short while, is to let the other end know we're connected, and it can start sending data.
    Last edited by Nominal Animal; 08-21-2014 at 04:43 PM.

  10. #10
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413
    I can try that tomorrow, but it's something not specific to RS485. I used two RS232 adapters and a DB9 null modem cable, no luck as well.

  11. #11
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by Epy View Post
    I used two RS232 adapters and a DB9 null modem cable, no luck as well.
    That does sound really, really odd.

    Could there be some other process accessing the device at the same time? lsof /dev/ttyUSB0 should tell..

  12. #12
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413
    By the way, I did this all on the linux computer: 2 RS232 adapters, connected together with null modem cable. Opened two SSH sessions tried to cat/echo between them, no luck. I've asked for some help over on the OpenWrt forum.

  13. #13
    Make Fortran great again
    Join Date
    Sep 2009
    Posts
    1,413
    Figured it out, and I feel like a total idiot.

    There is a known stability issue with USB on the particular router/CPU I'm using (this is a wireless router running OpenWrt), and the fix is basically to use a USB hub, so I was using a USB hub. Got rid of the USB hub and it worked perfectly. .........

    Guess I'll need to get a different hub.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. RS232 serial port library for Linux and Windows
    By Theodoor in forum Networking/Device Communication
    Replies: 8
    Last Post: 09-26-2009, 06:45 AM
  2. Replies: 17
    Last Post: 07-14-2009, 08:17 AM
  3. Linux serial port interrupts
    By danga1993 in forum Linux Programming
    Replies: 1
    Last Post: 04-28-2007, 11:15 AM
  4. Serial port programming in Linux
    By g4j31a5 in forum Linux Programming
    Replies: 20
    Last Post: 11-06-2006, 10:44 PM
  5. Serial port programming in Linux
    By g4j31a5 in forum C++ Programming
    Replies: 1
    Last Post: 09-28-2006, 08:24 PM