en / de
AI
Expertisen
Methoden
Dienstleistungen
Referenzen
Jobs & Karriere
Firma
Technologie-Trends TechCast WebCast TechBlog News Events Academy

Virtual pty/tty uart listener: Pitfalls on linux socat

by Sandro Klarer 02. März 2023· 3 Min. lesen

As a hardware and embedded engineer you come across of a lot of good and bad tools (hardware and software). One of our team’s nifty tools is a tty uart listener and protocol decoder. It is basically two FTDI UARTs that connect there RX to any signal on the UART of interest. Nothing fancy, but together with our Python script for decoding all the messages, this tool is very helpful for real time logging/debugging. It looks like this:

tty uart listener HW setup

This tool works fine. Alternatively, we could use a logic analyser and implement a protocol decoder. A sales logic analyser, for example, would support this. But now we have a new challenge: A virtual serial connection to a maintenance tool on a computer. The maintenance tool is developed by a different department, but the serial protocol is the same. So for debugging purposes it would be great to use our Sniffer SW tool as it is. The approach is to create two virtual serial tty UART listeners on my Linux machine. This should look like this:

tty uart listener

tty uart listener virtual setup

Ok, creating virtual tty (pty) and redirecting them sounds like what socat is made for that. Lets give it a try.

UDP try

UDP seems to be the first choice as the UART packets are connectionless like UDP. However, this approach did not work.

               Port xx16    Portxx17
Virtual_A  =><==( o===========o )===== Virtual_B
           


socat commands:

sudo socat -d -d PTY,raw,echo=0,link=/dev/ttyVA00,nonblock UDP-LISTEN:11316,reuseaddr,fork
sudo socat -d -d PTY,raw,echo=0,link=/dev/ttyVB00,nonblock UDP-LISTEN:11317,reuseaddr,fork
sudo socat -d -d UDP:localhost:11316 UDP:localhost:11317

The listener connects only after receiving data. As both listeners are not receiving data, the connection is never established → try TCP

sudo socat -d -d PTY,raw,echo=0,link=/dev/ttyVA00,nonblock TCP-LISTEN:11316,reuseaddr,fork
sudo socat -d -d PTY,raw,echo=0,link=/dev/ttyVB00,nonblock TCP-LISTEN:11317,reuseaddr,fork
sudo socat -d -d TCP:localhost:11316 TCP:localhost:11317

OK, the TCP approach works.

sudo on the virtual tty

It’s a bit tedious to always use sudo prevelage to connect to the virtual port.

This post helps:  https://unix.stackexchange.com/questions/374916/how-to-use-virtual-serial-port-without-root-privileges

sudo socat -d -d PTY,raw,echo=0,link=/dev/ttyVA00,nonblock,group-late=dialout,mode=660 xxxx

Duplicate an UART stream

So, I want to duplicate a data stream. One stream as the normal data flow and the other to feed our debug tool :

           Port xx16    Portxx17
Virtual_ttyVA00 ----( o-->----o )----- Virtual_ttyVB00
                      o
                       \     Portxx18
                        ---->--o )---- Virtual_ttyVC00

And these are the socat commands for it:

sudo socat -d -d PTY,raw,echo=0,link=/dev/ttyVA00,nonblock,group-late=dialout,mode=660 TCP-LISTEN:11316,reuseaddr,fork
sudo socat -d -d PTY,raw,echo=0,link=/dev/ttyVB00,nonblock,group-late=dialout,mode=660 TCP-LISTEN:11317,reuseaddr,fork
sudo socat -d -d PTY,raw,echo=0,link=/dev/ttyVC00,nonblock,group-late=dialout,mode=660 TCP-LISTEN:11318,reuseaddr,fork
sudo socat -u TCP:localhost:11316 - | tee >(socat - UDP:localhost:11317) >(socat - UDP:localhost:11318) > /dev/null

It works fine. I can connect to my three UART ports and send and receive both streams. Great, I think I’m done. Just need to put it all together.

 

The missing functionality in TCP

After hours of trying to set this up, I have finally isolated the missing piece of why it does not work. It’s not possible to split it into two paths.

          Port xx16            Portxx17
Virtual_A  ----( o------>---------o )----- Virtual_B
                  o               o
                   \             /    
                    -----<-------

 

And these are the socat commands:

sudo socat -d -d PTY,raw,echo=0,link=/dev/ttyVA00,nonblock,group-late=dialout,mode=660 TCP-LISTEN:11316,reuseaddr,fork
sudo socat -d -d PTY,raw,echo=0,link=/dev/ttyVB00,nonblock,group-late=dialout,mode=660 TCP-LISTEN:11317,reuseaddr,fork

sudo socat -u TCP:localhost:11316 TCP:localhost:11317 
sudo socat -U TCP:localhost:11316 TCP:localhost:11317

One path works, but when you try to send on the other path, it tries to send on the read connection and fails.

 

Using the socat -x option

Finally, I tried the -x option. So I got all the traffic streamed to stderr. I used tee to duplicate my stream (line 2) and separated the two streams with sed (lines 3 and 4). It took me a while to figure out why xxd (which converts hex output to binary output) was not outputting anything, so I had to add stdbuf -o0 to make sure there was no buffer.

sudo socat -x PTY,raw,echo=0,link=/dev/ttyVA00,nonblock,group-late=dialout,mode=660 PTY,raw,echo=0,link=/dev/ttyVB00,nonblock,group-late=dialout,mode=660 2> \
(tee \
(sed -u -n '/>/{n;p;}' > >(stdbuf -o0 xxd -r -p > >(sudo socat - PTY,raw,echo=0,link=/dev/ttyVC00,nonblock,group-late=dialout,mode=660))) \
(sed -u -n '/</{n;p;}' > >(stdbuf -o0 xxd -r -p > >(sudo socat - PTY,raw,echo=0,link=/dev/ttyVD00,nonblock,group-late=dialout,mode=660)))

Solved, finally.

socat help: http://rpm.pbone.net/manpage_idpl_25675711_numer_1_nazwa_socat.html

Kommentare

Schreiben Sie einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Newsletter - aktuelle Angebote, exklusive Tipps und spannende Neuigkeiten

 Jetzt anmelden

Copyright © 2025 Noser Engineering AG – Alle Rechte vorbehalten.

NACH OBEN
Privacy Policy Cookie Policy
Zur Webcast Übersicht