How do I bridge two physical serial ports to each other in software (and log the data going across)?

 ̄綄美尐妖づ 提交于 2020-01-01 10:31:39

问题


Basically, I want to put my computer in the middle of a serial line and record the conversation going across it. I'm trying to reverse engineer this conversation and eventually emulate one end of the conversation.

Rough Diagram of what I'm trying to do:

Normally, I have this:

__________        __________  
|        |        |        |  
|Device 1|<======>|Device 2|  
|________|        |________|  

I want to do this:

__________     __________     __________  
|        |     |        |     |        |  
|Device 1|<===>|Computer|<===>|Device 2|  
|________|     |________|     |________|  

With the computer in the middle basically bridging the connection between the two devices and logging the data that goes across.

Answers using any programming language are probably useful. Preferably I would be able to do this on either Windows or Linux (or both if someone has a general solution to this problem).


回答1:


Well, a programmatic way to do it would be to just open the relevant devices, and start forwarding data between them, simultaneously saving to a file.

Most any language can do it. There are nice libraries for things like java and python.

Several implementations exist on the web, I found a python one called Telnet Serial Bridge (TSB) by googling, which would allow you to bridge connections together over ethernet, and log using telnet tools like putty.

Though in the past, I've used the java rxtx serial comm library from rxtx.qbang.org to do it myself, though I suspect there's an updated version now, or maybe something built into the JVM proper.

Adapted from an example on that site:

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class TwoWaySerialComm
{
    void bridge( String portName1, String portName2 ) throws Exception
    {
        CommPortIdentifier portIdentifier1 = CommPortIdentifier.getPortIdentifier(portName1);
        CommPortIdentifier portIdentifier2 = CommPortIdentifier.getPortIdentifier(portName2);

        if ( portIdentifier1.isCurrentlyOwned() || portIdentifier2.isCurrentlyOwned())
        {
            System.out.println("Error: Port is currently in use");
        }
        else
        {
            CommPort commPort1 = portIdentifier1.open(this.getClass().getName(),2000);
            CommPort commPort2 = portIdentifier2.open(this.getClass().getName(),2000);

            if ( commPort instanceof SerialPort && commPort2 instanceof SerialPort )
            {
                SerialPort serialPort1 = (SerialPort) commPort1;
                serialPort1.setSerialPortParams(57600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);

                InputStream in1 = serialPort1.getInputStream();
                OutputStream out1 = serialPort1.getOutputStream();

                SerialPort serialPort2 = (SerialPort) commPort2;
                serialPort2.setSerialPortParams(57600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);

                InputStream in2 = serialPort2.getInputStream();
                OutputStream out2 = serialPort2.getOutputStream();

                (new Thread(new SerialReader(in1, out2))).start();
                (new Thread(new SerialReader(in2, out1))).start();
            }
            else
            {
                System.out.println("Error: Only serial ports are handled by this example.");
            }
        }     
    }

    /** */
    public static class SerialReaderWriter implements Runnable 
    {
        InputStream in;
        OutputStream out;

        public SerialReader ( InputStream in, OutputStream out )
        {
            this.in = in;
            this.out = out;
        }

        public void run ()
        {
            byte[] buffer = new byte[1024];
            int len = -1;
            try
            {
                while ( ( len = this.in.read(buffer)) > -1 )
                {
                    out.write(buffer,0, len);
                    System.out.print(new String(buffer,0,len));
                }
            }
            catch ( IOException e )
            {
                e.printStackTrace();
            }            
        }
    }

    public static void main ( String[] args )
    {
        try
        {
            (new TwoWaySerialComm()).bridge("COM1", "COM3");
        }
        catch ( Exception e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}



回答2:


I can offer a solution for Windows using 2 software utilities:

TCP COM Bridge - can connect 2 COM port over internal TCP connection. Advanced Serial Port Monitor - can monitor and record the conversation between devices.

Both utilities are here: http://www.aggsoft.com/




回答3:


Well, I'm a novice and since you didn't say anything about the platform you’re on, I'll tell you what I did, but I'll warn you in advance, this depends on software you may or may not have and this may not actually be an answer at all, so caveat lector.

My hardware is a MacBook Pro 2.4 GHZ running 10.7.5 with 4GB ram. What I was trying to do was read the serial comm chatter from an application that was running in Wine (since the application was windows based, but I didn’t want to use windows (icky poo). Heck , I didn’t want to use mac either, but I wasn’t making the headway I wanted to in virtual linux either, add to that Ubuntu is a little weird in the direction they’ve taken with some of the nitty gritty command-line “schtuff”.

Required software to start. Parallels Desktop Build 7.0.15107 (Might be able to do this in Virtual Box, I haven't tried) MultiCom (Freeware By Martin Louis for Mac) http://members.iinet.net.au/~mgl/MartysPlace/MultiCom.html Ubuntu 8.0.4 Hardy Heron

There maybe other ways, I must have chased down about a dozen ways to do what I wanted to do and I'm not happy yet with the output so this maybe a huge waste of time.

This solution doesn't use

  • strace
  • ttysnoop
  • gpspipe
  • socat
  • pyserial

And to be honest, ttysnoop seemed to be exactly what I wanted, socat seemed like a distant 2nd but a little too much for a novice imo.

The problems I ran into with other clients (possibly due to my inability to figure out how to change features about com connections) had to do with blocking. What you want, when you monitor a serial port, is a non-blocking connection. So you just listen to the port chatter and don’t interfere.

If you make a connection to it with clients like...

  • jpnevulator
  • minicom
  • cutecom
  • screen, etc.

...it seems that they take over the com port and the serial port is suddenly not available for you to monitor. There must be a way to configure them so this isn’t the case but I couldn’t figure it out. Add to that the complication that if you try to monitor from the mac side what the ports in your virtual machine are doing, it’s a little stickier still or trying to use any way you can to get past this “bump” of how to send the same data to 2 serial ports. So if you're smarter than me, I invite you to please make me less dumb.

On the Mac Side…

  • Launch MultiCom

Set – Port A

  • a) Configure as a Serial
  • b) Serial Device /dev/cu.KeySerial (in my case, you’ll need to discover what port you need heuristically using Terminal and typing ls /dev/tty.*
  • c) Click “Ok” and select the enable check box.

Set – Port B

  • a) Socket File Server
  • b) Socket File : /Users/shadowwraith/Desktop/socket.txt

On Virtual Machine Side (Parallels Ubuntu 8.0.4)

  • a) With the VM shutdown configure add 2 serial ports that reference the same socket file as CLIENTS (not servers) by specifying the full path.
  • b) Enable both by selecting the check box (Note: remember as far as the VM is concerned there is no USB connection to the serial device. You’re making that connection via the MultiCom software (or someother means if you know of one, what MultiCom is doing is acting as a conduit for the single port connection to the USB serial connector then duplicating all I/O to the socket file server which all the clients can connect to which can be multiple VMs or multiple serial ports in the same VM.)
  • c) Boot VM and set one serial port for your program and the other serial port for your sniffing. And POOF..there you go.

See below for more technical minutia about what to do... Linux How to display a serial port? dmesg | grep tty

This is what you would type in to get the sniffer to read the input assuming the serial port you chose to actively use a serial connection was on the other socketed port, ttyS0 at com 1 for instance (ttyS1 is at com 3 in this but you can figure this out by using dmesg | grep tty).

Seeing the information… jpnevulator --ascii --timing-print --tty "/dev/ttyS1" –read


Unrelated information that you shouldn’t use, but lead-up to me understanding why it was the wrong way to do this…

How to map a com port in linux (when you’re not worried about sniffing a port or using configure to add the serial ports)? ln -s /dev/ttyUSB0 com3

To undo this type unlink com3

Where ttyUSB0 is the port found from dmesg | grp tty and com3 is the desired port for Wine. This is done in the ~/.wine/dosdevices directory.




回答4:


This is a small python script to bridge between two physical ports` #!/usr/bin/python

import time, sys, serial
import collections
import re
from serial import SerialException
from termcolor import colored

SERIALPORT1 = "/dev/rfcomm0"  # the default com/serial port the receiver is connected to
BAUDRATE1 = 115200      # default baud rate we talk to Moteino

SERIALPORT2 = "/dev/ttyUSB0"  # the default com/serial port the receiver is connected to
BAUDRATE2 = 9600      # default baud rate we talk to Moteino


# MAIN()
if __name__ == "__main__":
    try:
        # open up the FTDI serial port to get data transmitted to Moteino
        ser1 = serial.Serial(SERIALPORT1, BAUDRATE1, timeout=1) #timeout=0 means nonblocking
        ser1.flushInput();
        print "\nCOM Port [", SERIALPORT1, "] found \n"
    except (IOError, SerialException) as e:
        print "\nCOM Port [", SERIALPORT1, "] not found, exiting...\n"
        exit(1)

    try:
        # open up the FTDI serial port to get data transmitted to Moteino
        ser2 = serial.Serial(SERIALPORT2, BAUDRATE2, timeout=1) #timeout=0 means nonblocking
        ser2.flushInput();
        print "\nCOM Port [", SERIALPORT2, "] found \n"
    except (IOError, SerialException) as e:
        print "\nCOM Port [", SERIALPORT2, "] not found, exiting...\n"
        exit(1)

    try:    

        while 1:
            ser1_waiting = ser1.inWaiting()
            if ser1_waiting > 0:
                #rx1 = ser1.read(ser1_waiting)
                rx1 = ser1.readline()
                ser2.write(rx1)
                print colored(rx1, 'red')
            ser2_waiting = ser2.inWaiting()
            if ser2_waiting > 0:
                #rx2 = ser2.read(ser2_waiting)
                rx2 = ser2.readline()
                ser1.write(rx2)
                print rx2       


    except IOError:
        print "Some IO Error found, exiting..." `



回答5:


For example take a cable from rx/tx of devices to the computer com port rx pin and run a terminal or serial port logger. Just that.



来源:https://stackoverflow.com/questions/4029255/how-do-i-bridge-two-physical-serial-ports-to-each-other-in-software-and-log-the

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!