Virtual Serial Port for Linux

218,121

Solution 1

You can use a pty ("pseudo-teletype", where a serial port is a "real teletype") for this. From one end, open /dev/ptyp5, and then attach your program to /dev/ttyp5; ttyp5 will act just like a serial port, but will send/receive everything it does via /dev/ptyp5.

If you really need it to talk to a file called /dev/ttys2, then simply move your old /dev/ttys2 out of the way and make a symlink from ptyp5 to ttys2.

Of course you can use some number other than ptyp5. Perhaps pick one with a high number to avoid duplicates, since all your login terminals will also be using ptys.

Wikipedia has more about ptys: http://en.wikipedia.org/wiki/Pseudo_terminal

Solution 2

Complementing the @slonik's answer.

You can test socat to create Virtual Serial Port doing the following procedure (tested on Ubuntu 12.04):

Open a terminal (let's call it Terminal 0) and execute it:

socat -d -d pty,raw,echo=0 pty,raw,echo=0

The code above returns:

2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/2
2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/3
2013/11/01 13:47:27 socat[2506] N starting data transfer loop with FDs [3,3] and [5,5]

Open another terminal and write (Terminal 1):

cat < /dev/pts/2

this command's port name can be changed according to the pc. it's depends on the previous output.

2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/**2**
2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/**3**
2013/11/01 13:47:27 socat[2506] N starting data transfer loop with FDs 

you should use the number available on highlighted area.

Open another terminal and write (Terminal 2):

echo "Test" > /dev/pts/3

Now back to Terminal 1 and you'll see the string "Test".

Solution 3

Use socat for this:

For example:

socat PTY,link=/dev/ttyS10 PTY,link=/dev/ttyS11

Solution 4

There is also tty0tty http://sourceforge.net/projects/tty0tty/ which is a real null modem emulator for linux.

It is a simple kernel module - a small source file. I don't know why it only got thumbs down on sourceforge, but it works well for me. The best thing about it is that is also emulates the hardware pins (RTC/CTS DSR/DTR). It even implements TIOCMGET/TIOCMSET and TIOCMIWAIT iotcl commands!

On a recent kernel you may get compilation errors. This is easy to fix. Just insert a few lines at the top of the module/tty0tty.c source (after the includes):

#ifndef init_MUTEX
#define init_MUTEX(x) sema_init((x),1)
#endif

When the module is loaded, it creates 4 pairs of serial ports. The devices are /dev/tnt0 to /dev/tnt7 where tnt0 is connected to tnt1, tnt2 is connected to tnt3, etc. You may need to fix the file permissions to be able to use the devices.

edit:

I guess I was a little quick with my enthusiasm. While the driver looks promising, it seems unstable. I don't know for sure but I think it crashed a machine in the office I was working on from home. I can't check until I'm back in the office on monday.

The second thing is that TIOCMIWAIT does not work. The code seems to be copied from some "tiny tty" example code. The handling of TIOCMIWAIT seems in place, but it never wakes up because the corresponding call to wake_up_interruptible() is missing.

edit:

The crash in the office really was the driver's fault. There was an initialization missing, and the completely untested TIOCMIWAIT code caused a crash of the machine.

I spent yesterday and today rewriting the driver. There were a lot of issues, but now it works well for me. There's still code missing for hardware flow control managed by the driver, but I don't need it because I'll be managing the pins myself using TIOCMGET/TIOCMSET/TIOCMIWAIT from user mode code.

If anyone is interested in my version of the code, send me a message and I'll send it to you.

Solution 5

You may want to look at Tibbo VSPDL for creating a linux virtual serial port using a Kernel driver -- it seems pretty new, and is available for download right now (beta version). Not sure about the license at this point, or whether they want to make it available commercially only in the future.

There are other commercial alternatives, such as http://www.ttyredirector.com/.

In Open Source, Remserial (GPL) may also do what you want, using Unix PTY's. It transmits the serial data in "raw form" to a network socket; STTY-like setup of terminal parameters must be done when creating the port, changing them later like described in RFC 2217 does not seem to be supported. You should be able to run two remserial instances to create a virtual nullmodem like com0com, except that you'll need to set up port speed etc in advance.

Socat (also GPL) is like an extended variant of Remserial with many many more options, including a "PTY" method for redirecting the PTY to something else, which can be another instance of Socat. For Unit tets, socat is likely nicer than remserial because you can directly cat files into the PTY. See the PTY example on the manpage. A patch exists under "contrib" to provide RFC2217 support for negotiating serial line settings.

Share:
218,121

Related videos on Youtube

JeffV
Author by

JeffV

Electronics Technologist, currently working as a Software Engineer on VR Simulation Systems. Primarily work in Modern C++, C (embedded), Java, C#. Involved in full engineering life cycle including requirements analysis, system decomposition, high level and low level design, implementation and system verification. Designed and implemented sonar processing systems for beam forming line arrays using distributed services and message passing with ZeroMQ. Designed and implemented VR training simulators with hardware stimulation. Designed and implemented wireless blasting receivers for through the earth communications. Extreme low power and reliability design goals: 6mos on a single C-cell battery. Spend my spare time with my wife and daughter, and enjoy mountain biking, boating, scuba, photography and flying. I like to ask the good questions so all can benefit from the answers. Hard to beat the fastest guns in the west around here. ;-)

Updated on November 29, 2021

Comments

  • JeffV
    JeffV over 2 years

    I need to test a serial port application on Linux, however, my test machine only has one serial port.

    Is there a way to add a virtual serial port to Linux and test my application by emulating a device through a shell or script?

    Note: I cannot remap the port, it hard coded on ttys2 and I need to test the application as it is written.

  • Matthew Smith
    Matthew Smith over 15 years
    On linux you can use the openpty / forkpty system calls. See man page
  • linjunhalida
    linjunhalida over 14 years
    how to create a virtual serial port pair by using command line tool?
  • Dima Tisnek
    Dima Tisnek about 12 years
    use chroot to to fake device names without affecting the system
  • Dima Tisnek
    Dima Tisnek about 12 years
    note that many serial port parameters, e.g. baudrate, parity, hw flow control, character size (?) are not implemented in pty, it is thus impossible to test your application in presence of serial transmission errors.
  • Exectron
    Exectron over 11 years
    This is helpful, but it describes the "old style" BSD pseudo-terminals. The "new style" UNIX 98 pseudo-terminals operate a bit differently—see pts man page for details.
  • apenwarr
    apenwarr over 11 years
    The advantage of using old-style ptys in this question is he really wanted one to be named /dev/ttys2. Old-style ptys can be renamed easily, new style ones not so much. Normal people should use new-style ptys as you say.
  • Exectron
    Exectron about 11 years
    I'd be interested to see your code. Can you contribute it back to the tty0tty project? However, I'd prefer to see people improve the pseudo-terminal code in the Linux kernel. E.g. add hardware handshaking support and TIOCMIWAIT.
  • Exectron
    Exectron almost 11 years
    "If anyone is interested in my version of the the code, send me a message and I'll send it to you." Yes, I'm interested! Can you point to it somewhere, e.g. on GitHub?
  • Peter Remmers
    Peter Remmers over 10 years
    I uploaded the driver to: github.com/pitti98/nullmodem Sorry it took so long to reply. I'm not very active on stackoverflow and overlooked your comment!
  • Peter Remmers
    Peter Remmers over 10 years
    No, I wrote it because I needed it and stopped once it was good enough to do what I wanted. Now that it's public, I hope it's useful for someone else, and maybe someone picks up where I left it.
  • László Papp
    László Papp over 10 years
    @MattSmith: do you actually have a working example for this with openpty? Just calling it is not enough to bind the one's output to the other's input, and vice versa...
  • Matthew Smith
    Matthew Smith over 10 years
    @LaszloPapp I got it working by following up the man pages for openpty and forkpty. I no longer have access to the source code as I have moved on from that company.
  • László Papp
    László Papp over 10 years
    @MattSmith: as I already wrote, openpty and forkpty are not enough on their own to establish a loopback! It is kind of strange, you do not even know the theory anymore... Anyway, I do not recommend this to others because I spent one full day without figuring out how to do it. It was a time waste.
  • Matthew Smith
    Matthew Smith over 10 years
    @LaszloPapp I do apologise, I was lying the whole time
  • gbmhunter
    gbmhunter over 10 years
    This worked well for me, tested with minicom! Seems as though the input to one terminal gets echoed to both (so it will reappear on the input terminal also).
  • gbmhunter
    gbmhunter over 10 years
    This worked better for me than slonik's answer, because it auto-assigns to virtual COM port files, and doesn't echo.
  • Maxthon Chan
    Maxthon Chan over 9 years
    Actually the null modem USB UART cables seem like quite an elegant solution to me as it supports both local testing (get an USB hub if you are short on ports) and remote debugging.
  • cptHammer
    cptHammer almost 8 years
    I don't have the same echo behavior ... minicom has a "local echo" feature... but when it is disabled, it works exactly as a real serial port would. thanks for the tip.
  • Patrick B.
    Patrick B. over 6 years
    If you want reproducible filename use link=/path/to/link after each device-declaration (after echo=0). It can thus be used in automated tests. (as slonik does in their answer)
  • Mattis Asp
    Mattis Asp over 6 years
    while (read(fd, &inputbyte, 1) == 1) { ... } read is undefined in your code. write is undefined. close is undefined.
  • Penghe Geng
    Penghe Geng over 5 years
    To create a pty that links to a real serial port: socat -d -d pty,raw,echo=0 /dev/ttyUSB5,raw,echo=0.
  • Daniel Santos
    Daniel Santos about 4 years
    @DimaTisnek I think it's about time for that to change! Just googling 'linux virtual serial port' to make sure I'm not off my rocker and re-writing the wheel. I think I'm going to add a CVSERIAL flag to the termios c_cflag field (lots of bits currently unused) as a switch to turn it on and off (from the master side, of course) and when set, the slave and master will have all of the modem control ioctls, except that the master will do all RI, CD, etc. lines. I guess we'll see if I can get it past the maintainers then.
  • Daniel Santos
    Daniel Santos about 4 years
    I haven't reviewed it's quality, but ttynvt implements RFC 2217 via Linux FUSE
  • Dima Tisnek
    Dima Tisnek about 4 years
    @DanielSantos sounds like a plan. Perhaps, depending on what you want to virtualise, such virtual serial "hardware" should be an own module... For example if you wanted to simulate baud rate mismatch. In any case, a flag sounds like a good way to start hacking!
  • mrid
    mrid about 4 years
    can i create a serial port with names like /dev/ttyS0 instead of /dev/pts/1 ?
  • Yves Lhuillier
    Yves Lhuillier over 3 years
    @MattisAsp has a point, you should at least include <unistd.h>. Plus there's a bunch of should-not-ignore-warnings fixable stuffs but overall simple code as I like.
  • jaromrax
    jaromrax about 3 years
    My pts terminal always dissapears on a first keypress- when connected with serial library from python.
  • Raleigh L.
    Raleigh L. over 2 years
    This doesn't appear to work without special permissions: ``` 2021/12/10 16:08:47 socat[90013] E unlink("/dev/ttyS10"): Permission denied ```
  • trampster
    trampster over 2 years
    I tried this but I can only open it once, (using c# SerialPort) eventhough a I dispose before trying to connect with a new instance it always crashes on the open