data-dancer
data-dancer

Reputation: 33

How to determine which pair of pseudo tty ports are connected to each other

I have two python programs that are to communicate with each other over a point to point tty serial connection. To simulate the connection, I create a bi-directional byte stream using socat as here:

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

The console returns the following, indicating the two pty ports that are now connected together:

2018/04/15 22:33:03 socat[18197] N PTY is /dev/pts/2
2018/04/15 22:33:03 socat[18197] N PTY is /dev/pts/3
2018/04/15 22:33:03 socat[18197] N starting data transfer loop with FDs [5,5] and [7,7]

Then I have to modify each of the two programs manually to specify the serial connection for each, such as:

In program A.py:

import serial
...
ser = serial.Serial('/dev/pts/2')

In program B.py:

import serial
...
ser = serial.Serial('/dev/pts/3')

What I'd like is a script that would set up the socat connection, then execute A.py with one port number passed to it as an argument, and execute B.py with the other port number passed to it as an argument.

I've tried a bash script, but the socat command blocks and I can't capture its stderr output to put it in a variable. If I could, I could then parse the variable and be on my merry way.

Any ideas? Or maybe a muy better way to do this?

Thank you!

Upvotes: 2

Views: 635

Answers (1)

tdelaney
tdelaney

Reputation: 77387

You can run socat without blocking using the low level Popen class in python. You need to redirect stderr so that you can scan it for the pty name, but then you can hand it off to a background thread after you get the information you want.

import sys
import subprocess as subp
import threading
import shutil
import re

socat_proc = subp.Popen(['socat', '-d', '-d', 'pty,raw,echo=0', 'pty,raw,echo=0'],
    stderr=subp.PIPE)

try:
    # scan output for 2 ptys
    ptylist = []
    for line in socat_proc.stderr:
        line = line.decode().strip()
        print(line)
        pty = re.search(r"N PTY is (.+)", line)
        if pty:
            ptylist.append(pty.group(1))
            if len(ptylist) == 2:
                break

    if socat_proc.poll() is not None:
        print("badness. socat dead.")
        exit(2)

    # background thread consumes proc pipe and sends to stdout
    socat_thread = threading.Thread(target=shutil.copyfileobj, 
        args=(socat_proc.stdout, sys.stdout))
    socat_thread.daemon = True
    socat_thread.start()

    print("pty", ptylist)

    # now you can start your programs...

finally:
    socat_proc.terminate()

Upvotes: 1

Related Questions