Linux Socat Virtual Serial Port

0 views
Skip to first unread message

Lorin Cupples

unread,
Aug 3, 2024, 4:05:57 PM8/3/24
to roigaumettfab

The modems are no longer available and therefore I need to develop some alternative. Therefore I thought I could run a simple python script on the SBC that would "intercept" the AT commands, send back the appropriate responses to the c# software and then I can use the python script to talk to another device however I need to.

The physical setup is that I currently have the serial port plugged into my laptop so I can see the AT commands coming up the pipe (on ttyS1) I then ssh into the SBC and fire up minicom to view the new "virtual ports" created by socat.

I can type into minicom on the SBC and see the output turning up on the serial port reader on my laptop, likewise I can type into the serial port reader on my laptop and see the input in minicom on the SBC, however what I cannot seem to intercept is the actual AT commands being sent from the c# software even though the software is configured to use ttyS1.

The one bit of control I do have over the software is which port it uses to talk to the modem on. Therefore I have also tried changing this to a virtual port e.g. /dev/ttyV1 and running socat to create the virtual port during startup and before the c# program starts so that the virtual port is actually available. Again I have exactly the same issue where I still cannot see the AT commands being sent by c# software.

Typically there would be a 1st socat command for the first half (the PTY) that would call with EXEC: an executable for traffic alteration (which can be a shell script or python or whatever and will have to manage both sides possibly using up to 4 different FDs) which would call a 2nd socat for the second half (ttyS1).

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!

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.

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.

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.

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.

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.

The code is pretty self explanatory. First, you create the master process by running ./main master and it will print to stderr the device is using. After that, you invoke ./main slave device, where device is the device printed in the first command.

RFC 2217 covers a com port to TCP/IP standard that allows a client on one system to emulate a serial port to the local programs, while transparently sending and receiving data and control signals to a server on another system which actually has the serial port. Here's a high-level overview.

What you would do is find or implement a client com port driver that would implement the client side of the system on your PC - appearing to be a real serial port but in reality shuttling everything to a server. You might be able to get this driver for free from Digi, Lantronix, etc in support of their real standalone serial port servers.

Alternately, the serial port driver source for Linux is readily available. Take that, gut the hardware control pieces, and have that one driver run two /dev/ttySx ports, as a simple loopback. Then connect your real program to the ttyS2 and your simulator to the other ttySx.

But the easiest thing to do right now? Spend $40 on two serial port USB devices, wire them together (null modem) and actually have two real serial ports - one for the program you're testing, one for your simulator.

Combining all other amazingly useful answers, I found the below command to be VERY useful for testing on different types of Linux distros where there's no guarantee you're going to get the same /dev/pts/#'s every time and/or you need to test multiple psuedo serial devices and connections at once.

This was all because I was trying running tests against a platform where I needed to generated a lot of mach-serial connections and to test their input/output via containerization (Docker). Hopefully someone finds it useful.

The server has a virtual com port, the same we set in the client config (e.g. COM1). When an application on the server writes data to this port, the data should be send to all clients connected via tcp. The response from the clients is send over TCP back to the server which can read it over the virtual serial port.

you have socat and ser2net and other programs but my experience is very bad... not working properly. I've done this small python program, can be useful. Update port, baudrate... then use any tcp client. Remove first line if don't want to use is as auto executable script

I use it for creating virtual serial communications over network, but I have the real RS232 port on the computer. So I just transfer the data over network. If you need to create a virtual COM on the server too, use the Virtual Serial Port Driver.

I have a scenario where I demonstrated to my group @ work how to share a very expensive USB patient simulator plugged into a Raspberry Pi (Debian) using socat. The group wants to be able to have an on-demand, bi-directional connection to the serial device over Ethernet. Presently I have the device broadcasting via Telnet.

I need to setup the consumer side whereby a Windows user connects to the Telnet port, but redirects the I/O to an available COM port on their machine. I was thinking Cygwin & socat on the Windows side, but I'm not a very skilled Windows guy.

There are open source applications for example in sourceforge.net that can connect tcp socket with a serial port in Windows. Also, just google "serial to ip" or "ip to serial".One simple example is "SerialToIP" =directory It is developed in C#. It has command line and GUI versions available, but serial port control is minimal but that might be enough for your needs based on the socat-example.

Depending on how detailed serial port control needs you have and if your application needs to run whether a Windows user is logged in or not, you should select the application that fits your needs. GUI applications in Windows by default require the user to be logged in to work.

BTW, your socat-command has nothing to do with the Telnet-protocol. You are just creating a pure and simple TCP/IP "pipe" that connects to a serial port. Any possible top-layer protocols carried inside that "pipe" are irrelevant to the question and answers.

The first pty options creates the virtual serial port. It turns out terminal echo using rawer. The port is created using the file id given by the link option. The EXEC option will run the executable (given by the COMMAND value) and connect to the virtual serial port using stdin & stdout.

As part of the testing process, I wanted to run the system tests in the CI/CD pipeline. This came with the challenge that the test environment would not have the device connected to the serial port. Thinking about how to handle this, I eventually settled on a neat solution using the socat utility.

Using the tool, I could create a virtual serial port in the test environment. This virtual serial port was configured to pipe all data transferred to an executable (using stdin and stdout). The embedded code was compiled into an executable for the test platform - using a custom runner script and a mock serial API which read from and wrote to stdin and stdout. The systems test just needed to use the virtual port name to run in the test environment without modification.

Being able to create virtual serial ports (which pipe data to stdin/stdout or custom executables) is a really useful feature for testing and debugging programs which use serial ports for communication!

I setup ser2net on the pi and installed Socat on the Debian box. I now have a virtual serial port (ttyNET0) on the laptop and can read data from the Arduino via the pi with a python script. So far, so good.

The only available port in my Arduino IDE in the Tools->Port menu is /dev/ttyS0. This is normally the first serial port (of a PC). As I don't have a physical serial port I reconfigured Socat to use ttyS0 as the virtual serial port. Good news is that the Serial Monitor function in the Arduino IDE is now working ok. Bad news is that I still am unable to download a sketch to my Arduino. I get the error messages as shown in the attached screenshot.

c80f0f1006
Reply all
Reply to author
Forward
0 new messages