138

Is there a way to connect to a serial terminal just as you would do with SSH? There must be a simpler way than tools such as Minicom, like this

$ serial /dev/ttyS0 

I know I can cat the output from /dev/ttyS0 but only one way communication is possible that way, from the port to the console. And echo out to the port is just the same but the other way around, to the port.

How can I realize two way communication with a serial port the simplest possible way on Unix/Linux?

1
  • 2
    Great answers people!. Unfortunately no one seem to fully fit my purpose when working with embedded systems with a limited set of commmands. I did however find another way using a shell scrip which I add as one of the answers to my question.
    – norq
    Oct 18, 2011 at 10:15

16 Answers 16

97

I find screen the most useful program for serial communication since I use it for other things anyway. It's usually just screen /dev/ttyS0 <speed>, although the default settings may be different for your device. It also allows you to pipe anything into the session by entering command mode and doing exec !! <run some program that generates output>.

6
  • 3
    +1 for screen! Also, see: serverfault.com/q/81544/11086
    – Josh
    Oct 14, 2011 at 13:16
  • 1
    See also noah.org/wiki/Screen_notes#using_screen_as_a_serial_terminal and the manual page stty(1), I had to add extra options (e.g. parity) for it to work.
    – Lekensteyn
    Mar 20, 2012 at 22:22
  • 3
    feels ashamed I wrongly connected the TX/RX :o
    – Lekensteyn
    Mar 20, 2012 at 22:50
  • 1
    screen is awesome, but I don't think it it simpler than minicom :-) May 29, 2017 at 16:57
  • 2
    @CiroSantilli刘晓波死六四事件法轮功 - Screen may be not simpler than Minicom but because I already use Screen, for me it is less complexity to do my serial stuff with Screen too eliminating the need for Minicom totally.
    – user62916
    Sep 2, 2017 at 13:02
69

Background

The main reason why you need any program like minicom to communicate over a serial port is that the port needs to be set up prior to initiating a connection. If it weren't set up appropriately, the cat and echo commands would not do for you what you might have expected. Notice that once you run a program like minicom, the port is left with the settings that minicom used. You can query the communication settings using the stty program like this:

stty < /dev/ttyS0

If you have done it right; after booting the computer and before running any other program like minicom, the communication settings will be at their default settings. These are probably different than what you will need to make your connection. In this situation, sending the commands cat or echo to the port will either produce garbage or not work at all.

Run stty again after using minicom, and you'll notice the settings are set to what the program was using.

Minimal serial communication

Basically, two things are needed to have two-way communication through a serial port: 1) configuring the serial port, and 2) opening the pseudo-tty read-write.

The most basic program that I know that does this is picocom. You can also use a tool like setserial to set up the port and then interact with it directly from the shell.

2
  • 7
    picocom also will let you connect to a serial port without reconfiguring it (--noinit) and will let you exit without restoring the serial port configuration (--noreset or use Ctrl-A/Ctrl-Q to quit picocom). I've found picocom to be much easier to use than minicom. For reasons I haven't figured out, minicom will sometime simply not send or receive data on a port that worked moments before or that picocom has no trouble with. It's probably some arcane configuration option, but whatever it is I can't figure it out (and this behavior has happened on more than one machine). Oct 24, 2013 at 21:11
  • 2
    +1 for picocom! I found that I wasn't able to write commands to the serial device without the correct line endings: I needed to use --omap crcrlf --echo options Oct 16, 2019 at 3:23
33

I found a way using a shell script in Serial Programming that runs cat as a background process and a while loop that reads the user input and echos it out to the port.  I modified it to be more general and it fit my purpose perfectly.

#!/bin/sh

# connect.sh

# Usage:
# $ connect.sh <device> <port speed>
# Example: connect.sh /dev/ttyS0 9600

# Let cat read the device $1 in the background
cat "$1" &

# Capture the PID of the background process (cat)
# so it is possible to terminate it when done.
bgPid=$!

# Set up device
stty -F "$1" "$2"


# Read commands from user, send them to device $1
while read cmd
do
   echo "$cmd" 
done > "$1"

# Terminate background read process
kill "$bgPid"
11
  • 1
    Also, I've made a slightly modified version below which can also send Ctrl+C and Ctrl+Z.
    – Fritz
    Sep 22, 2016 at 17:06
  • @Fritz Nice find! So if I get this right, the background process would never be killed because $? doesn't seem to expand to anything right?
    – norq
    Sep 26, 2016 at 6:23
  • 1
    @ihatetoregister: Not quite correct. The background process is killed, but not for the reasons one might expect. $? expands to the exit code of the last non-background command (in this case stty -F $1 $2), so it expands to 0 when there was no error. Thus, the last line becomes kill 0 which in turn seems to kill the current shell and all its children (it behaves differently in interactive shells I believe). For all the details see the following explanation: unix.stackexchange.com/questions/67532/…
    – Fritz
    Sep 26, 2016 at 9:03
  • 1
    Howerver, the real gotcha in your script is that the background process is only killed if you press Ctrl+D to end your script, because that ends the while loop cleanly. If you kill it with Ctrl+C or with the kill command, then the cat process stays alive. To fix that you would need to use the trap command to execute kill $bgPid when the shell exits, like my script down below does. Honestly, I wouldn't even mind if you just added my whole script to your post. I tried to do that, but the edit was rejected.
    – Fritz
    Sep 26, 2016 at 11:08
  • 1
    @G-ManSays'ReinstateMonica': i didn't know that. So thank you.
    – gerhard d.
    Sep 22, 2022 at 8:29
32

If UUCP is installed on the system, you may use the command cu, e.g.

 $ cu -l /dev/ttyS0 -s 9600
2
  • 5
    Use ~^D or ~. to exit.
    – iman
    Sep 14, 2019 at 7:57
  • Dear gods, I'd forgotten cu ("call up") - the last time I used that command, Linus was in the Finnish version of High School! But that's the exact command I need right now, so thanks for the reminder - and the memories, @ktf.
    – Jon Green
    Nov 30 at 11:14
27

Try http://tio.github.io

"tio" is a simple TTY terminal application which features a straightforward commandline interface to easily connect to TTY devices for basic input/output.

Typical use is without options. For example:

tio /dev/ttyS0

Which corresponds to the commonly used options:

tio --baudrate 115200 --databits 8 --flow none --stopbits 1 --parity none /dev/ttyS0

It comes with full shell auto completion support for all options.

1
  • 4
    I'm using msys2 on Windows and you can install tio with pacman -S tio because it's among the available packages by default. screen, picocom, etc. are not. Thanks! May 23, 2018 at 13:11
21

This script is based on another answer, but sends everything over the serial port (except Ctrl+Q), not just single commands followed by Enter. This enables you to use Ctrl+C or Ctrl+Z on the remote host, and to use interactive "GUI" programs like aptitude or alsamixer. It can be quit by pressing Ctrl+Q.

Just put the following code into a file /usr/local/bin/femtocom (or any other place in $PATH) and do chmod +x /usr/local/bin/femtocom.

From there on you can connect to any serial port like this for example:

femtocom /dev/ttyUSB0 57600

#!/bin/bash

if [[ $# -lt 1 ]]; then
    echo "Usage:"
    echo "  femtocom <serial-port> [ <speed> [ <stty-options> ... ] ]"
    echo "  Example: $0 /dev/ttyS0 9600"
    echo "  Press Ctrl+Q to quit"
fi

set -e    # Exit when any command fails

# Save settings of current terminal to restore later
original_settings="$(stty -g)"

# Kill background process and restore terminal when this shell exits
trap 'set +e; kill "$bgPid"; stty "$original_settings"' EXIT

# Remove serial port from parameter list, so only stty settings remain
port="$1"; shift

# Set up serial port, append all remaining parameters from command line
stty -F "$port" raw -echo "$@"

# Set current terminal to pass through everything except Ctrl+Q
# * "quit undef susp undef" will disable Ctrl+\ and Ctrl+Z handling
# * "isig intr ^Q" will make Ctrl+Q send SIGINT to this script
stty raw -echo isig intr ^Q quit undef susp undef

echo "Connecting to $port. Press Ctrl+Q to exit."

# Let cat read the serial port to the screen in the background
# Capture PID of background process so it is possible to terminate it
cat "$port" & bgPid=$!

cat >"$port"   # Redirect all keyboard input to serial port
3
  • 1
    BTW, I use this script many times a day; thanks. Sep 2, 2022 at 12:19
  • @Fritz your clever script works very well but how could I modify it to read from the serial port into a variable and test that variable to take action depending on what is received? I tried to assign my_var= $(cat "$port"), use a read in a while loop with nested if but not only it doesn't read properly into my variable but also I lose the trick to catch the background PID...
    – calocedrus
    Oct 19, 2022 at 8:05
  • @calocedrus: You should ask a separate question about that. The purpose of this script and question is completely different from what you want to do, so the solution will be completely different from this script.
    – Fritz
    Oct 20, 2022 at 14:16
7

BTW, the putty package (which does run on Linux) does include serial support.

6

Another issue that can occur is that your user account may need to set to the "dialout" group to access the serial port.

sudo usermod -a -G dialout $USER
3

Putty works well on Linux and offers some convenience, especially for serial communications. It has one drawback I haven't been able to directly solve: no copy-paste from the Putty window itself. The windows version has a lovely auto-copy to clipboard on highlight, right-click to paste behaviour (and there are excellent plugins for both chrome and firefox to enable the same behavior), but on Linux, no copy love AFAIK.

If the lack of copy is a problem (it is for me) then turn on logging in putty and open a standard terminal window and # tail -f putty.log and bidirectional text is available for standard copypasta action.

1
  • 1
    I find that Putty under Linux doesn't paste "the clipboard" (what you copy with control-C), but it will insert "the primary selection" (what you have currently selected in some program) with middle-mouse. Likewise you can select characters in Putty's screen to define the primary selection. But if I want text from a Putty screen to transfer to some VM, I need it to be the clipboard, so I have to use an intermediary program to receive the text from the main selection and then copy it to the clipboard. Feb 28, 2017 at 19:58
3

As mentioned before you can try picocom. The latest release (2.0) can also be used (safely) to set-up a "terminal server" since it no longer permits shell command injection. See:

https://github.com/npat-efault/picocom/releases

3

I wonder why nobody mentioned ser2net.

Example /etc/ser2net.conf:

3000:telnet:600:/dev/ttyUSB0:115200 8DATABITS NONE 1STOPBIT
3001:telnet:600:/dev/ttyUSB1:115200 8DATABITS NONE 1STOPBIT
3002:telnet:600:/dev/ttyUSB2:115200 8DATABITS NONE 1STOPBIT
3003:telnet:600:/dev/ttyUSB3:115200 8DATABITS NONE 1STOPBIT

You can connect to serial port as easy as:

telnet localhost 3000

Or remotely:

telnet <ip> 3000

Or even set up port forwarding on your router and expose it to Internet, so that you could connect to it from anywhere (let's skip security issues, I'm talking about flexibility).

3

As it is not mentioned here already, I'd also mention socat - more info in https://stackoverflow.com/questions/2899180/how-can-i-use-com-and-usb-ports-within-cygwin :

socat `tty`,raw,echo=0 /dev/ttyS15,raw,echo=0,setsid,sane

or

socat - /dev/ttyS15,raw,echo=0,setsid,sane

(though, I've had the problem of stopping it once it starts running, under MSYS2 on Windows)

2

It depends on what you want to do. Do you want to run a shell or applicaiton interactively from the terminal, connect out to another computer over the serial line, automate communication with a device over a serial port?

If you want bidirectional communication then I presume you want something interactive with a human on the terminal. You can configure the system to allow logins from a terminal over a serial port by seting up a getty(1) session on the serial port - getty is the tool for setting up a terminal and allowing logins onto it. Put an entry in your inittab(5) file to run it on the appropriate serial port on a respawn basis.

If you want to connect to a device and initiate automated two way conversations then you could see if expect will get you what you want. Use stty(1) to configure the port to the right parity, baud rate and other relevant settings.

If you want to communicate interactively with another computer over the serial port then you will need terminal emulation software. This does quite a lot - it sets up the port, interprets ANSI or other terminal command sequences (ANSI was far from being the only standard supported by serial terminals). Many terminal emulators also support file transfer protocols such as kermit or zmodem.

The ins and outs of serial communications and terminal I/O are fairly complex; you can read more than you ever wanted to know on the subject in the serial howto.

2

You need to be sure to have the correct read write permits on the device, you could see it with:

$ls -l /dev/[serial device]

I rely on the script you found and made some modifications.

For the development systems I've used by now, they used to need:

  • None parity and
  • One stop bit

Those values are the default ones in the script.

So in order to connect, you can use it as simple as follows:

./connect.sh /dev/[serial device] [baud speed]

Example:

$./connect.sh /dev/ttyUSB0 19200

Script:

#!/bin/bash

# connect.sh


#Taken from example modified by: ihatetoregister
# On stack exchange, thread:
# http://unix.stackexchange.com/questions/22545/how-to-connect-to-a-serial-port-as-simple-as-using-ssh
# Modified by Rafael Karosuo <[email protected]>
#   - parity enabling and amount of stop bits
#   - no execution without minimum params
#   - exit code for stty
#   - bgPid fix, used $! instead of $? to take the PID of cat proc in background.
#   - exit command to end the program
#   - CR termination and strip of NL added by READ command, in order to make $cmd\r\n format instead of \n$cmd\n


# Usage:
# $./connect.sh <device> <port speed> [# Stop bits] [parity]

# Stop bits 1|2
# Parity even | odd

# If no last two params, then default values stopbits=1, parity=disab

# Example: 
# connect.sh /dev/ttyS0 9600 1 even, this will use 1 stop bit and even parity
# connect.sh /dev/ttyS0 9600, this will take default values for parity and stopbit


#Check if at least port and baud params provided
if [ -z "$1" ] || [ -z "$2" ]; then
    printf "\nusage: ./connect.sh <device> <port speed> [# Stop bits 1|2] [parity even|odd]\n\tNeed to provide at least port and baud speed parameters.\n\texample:connect.sh /dev/ttyS0 9600\n\n"
    exit 1;
else
    case "$3"   in
        2) stopb="cstopb";;
        *) stopb="-cstopb";;
    esac

    if [ "$4" = "even" ]; then
        par="-parodd"
    elif [ "$4" = "odd" ]; then
        par="parodd"
    else
        par="-parity"
    fi
    printf "\nThen stty -F $1 $2 $stopb $par\n";
fi

# Set up device
stty -F "$1" "$2" "$stopb" "$par" -icrnl

# Check if error ocurred
if [ "$?" -ne 0 ]; then
    printf "\n\nError ocurred, stty exited $?\n\n"
    exit 1;
fi

# Let cat read the device $1 in the background
cat -v "$1" &

# Capture PID of background process so it is possible to terminate it when done
bgPid="$!"

# Read commands from user, send them to device $1
while [ "$cmd" != "exit" ]
do
   read cmd
   echo -e "\x08$cmd\x0D" > "$1" #strip off the \n that read puts and adds \r for windows like LF

done

# Terminate background read process
kill "$bgPid"

P.S.: You need to know which kind of line feed is using your receiver system since this will determine how you'll need to send the commands in my case I needed a Windows like LF, means that I need to send

command\r

ASCII values for:

  • LF : 0Ah, line feed "\n"
  • CR : 0Dh, carrige return "\r"
  • BS : 08h, back space "<-"
1
  • 1
    (1) #!/bin/sh is ignored if it isn’t the first line of the file.  (2) Seriously?  You’re using 1 to specify even parity and 2 to specify odd?  (3) It’s conventional to have a “usage” or “help” message that documents all the parameters, not just the mandatory ones.  (4)  You should always quote your shell variable references (e.g., "$1", "$2", "$3", "$4", "$stopb", "$par", "$bgPid", and even "$?" and "$!") unless you have a good reason not to, and you’re sure you know what you’re doing. Jul 9, 2016 at 7:15
1

You might want to take a look at

http://serialconsole.sourceforge.net

Pro: doesn't have obvious security problems like minicom or picocom (if you don't have a problem giving the users shell access, no problem, but you most likely do have one if you want to set up a terminal server...)

0

Another easy option is to access the machine over ssh with the -X flag and run a program such as putty or gtkterm.

So:

$ ssh -X <user>@<machine_address>

$ sudo apt-get install gtkterm (if not installed already)

$ gtkterm

It should launch the graphical interface on your client PC and from there you can access the serial port as if you would be in the host.

Disclaimer: Only tried this with ubuntu machines. I'm guessing that it won't work with machines without graphic interfaces.

From the ssh manual:

-X

Enables X11 forwarding. This can also be specified on a per-host basis in a configuration file. X11 forwarding should be enabled with caution. Users with the ability to bypass file permissions on the remote host (for the user's X authorization database) can access the local X11 display through the forwarded connection. An attacker may then be able to perform activities such as keystroke monitoring. For this reason, X11 forwarding is subjected to X11 SECURITY extension restrictions by default. Please refer to the ssh -Y option and the ForwardX11Trusted directive in ssh_config(5) for more information.

-Y

Enables trusted X11 forwarding. Trusted X11 forwardings are not subjected to the X11 SECURITY extension controls.

So use -Y if security is an issue.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .