如何在软件中将两个物理串行端口相互桥接(并记录穿过的数据)?

发布于 2024-09-29 09:59:55 字数 599 浏览 0 评论 0原文

基本上,我想将我的计算机放在串行线中间并记录通过它的对话。我正在尝试对这段对话进行逆向工程,并最终模拟对话的一端。

我想要做的粗略图:

通常情况下,我有这个:

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

我想这样做:

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

中间的计算机基本上桥接两个设备之间的连接并记录所经过的数据。

使用任何编程语言的答案可能都是有用的。最好我能够在 Windows 或 Linux 上执行此操作(或者如果有人对此问题有通用解决方案)。

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).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

甜心 2024-10-06 09:59:55

那么,一种编程方法就是打开相关设备,然后开始在它们之间转发数据,同时保存到文件中。

大多数任何语言都可以做到。对于 java 和 python 之类的东西有很好的库。

网络上存在多种实现,我通过谷歌搜索找到了一种名为 Telnet Serial Bridge (TSB) 的 Python 实现,它允许您通过以太网桥接连接,并使用 putty 等 telnet 工具进行日志记录。

虽然在过去,我使用过 rxtx.qbang.org 中的 java rxtx 串行通信库 自己做,尽管我怀疑现在有更新的版本,或者可能是 JVM 中内置的东西。

改编自该网站上的示例:

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();
        }
    }
}

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();
        }
    }
}
小清晰的声音 2024-10-06 09:59:55

这是一个小的 python 脚本,用于在两个物理端口之间进行桥接 #!/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..." `

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..." `
罪#恶を代价 2024-10-06 09:59:55

我可以使用 2 个软件实用程序为 Windows 提供解决方案:

TCP COM Bridge - 可以通过内部 TCP 连接连接 2 个 COM 端口。
高级串行端口监视器 - 可以监视和记录设备之间的对话。

这两个实用程序都在这里:
http://www.aggsoft.com/

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/

默嘫て 2024-10-06 09:59:55

好吧,我是新手,既然你没有说任何关于你所在平台的信息,我会告诉你我做了什么,但我会提前警告你,这取决于你可能会或可能不会的软件有,这实际上可能根本不是答案,所以请注意讲师。

我的硬件是 MacBook Pro 2.4 GHZ,运行 10.7.5,具有 4GB 内存。
我想做的是从 Wine 中运行的应用程序中读取串行通信信息(因为该应用程序是基于 Windows 的,但我不想使用 Windows(讨厌的便便)。哎呀,我不想 有点奇怪。

也可以使用 mac,但我在虚拟 Linux 方面也没有取得我想要的进展,而且 Ubuntu 在使用一些具体的命令行“schtuff”所需的软件方面 开始。
Parallels Desktop Build 7.0.15107(也许可以在 Virtual Box 中执行此操作,我还没有尝试过)
MultiCom(Martin Louis 的 Mac 免费软件)
http://members.iinet.net.au/~mgl/MartysPlace/MultiCom .html
Ubuntu 8.0.4 Hardy Heron

也许还有其他方法,我必须寻找大约十几种方法来做我想做的事情,但我对输出还不满意,所以这可能是浪费时间。

这个解决方案不使用

  • strace
  • ttysnoop
  • gpspipe
  • socat
  • pyserial

说实话,ttysnoop 似乎正是我想要的,socat 似乎是一个遥远的第二个,但对于新手来说有点太多了。

我在其他客户端上遇到的问题(可能是由于我无法弄清楚如何更改有关 com 连接的功能)与阻塞有关。当您监视串行端口时,您想要的是非阻塞连接。所以你只需要听端口的喋喋不休,不要干涉。

客户端建立连接

  • 如果您与诸如jpnevulator
  • minicom
  • Cutecom
  • screen 等

...它们似乎接管了 com 端口,并且串行端口突然无法供您监控。必须有一种方法来配置它们,所以情况并非如此,但我无法弄清楚。更复杂的是,如果您尝试从 mac 端监控虚拟机中的端口正在做什么,那么仍然有点棘手,或者尝试使用任何方法来克服如何发送数据的“障碍”。相同的数据传输到 2 个串行端口。所以,如果你比我聪明,我邀请你让我变得不那么愚蠢。

在 Mac 端...

  • 启动 MultiCom

设置 - 端口 A

  • a) 配置为串行
  • b) 串行设备 /dev/cu.KeySerial(在我的情况下,您需要使用终端并输入 ls /dev/tty.* 试探性地发现您需要的端口。
  • c) 单击“确定”并选择启用复选框。

设置 – 端口 B

  • a) 套接字文件服务器
  • b) 套接字文件:/Users/shadowwraith/Desktop/socket.txt

在虚拟机端 (Parallels Ubuntu 8.0.4)

  • a )在 VM 关闭时,配置添加 2 个串行端口,通过指定完整路径引用与客户端(而非服务器)相同的套接字文件。
  • b) 通过选中复选框来启用两者(注意:记住,就虚拟机而言,串行设备没有 USB 连接。您可以通过 MultiCom 软件(或者其他方式,如果您知道其中一种,则可以)进行连接, MultiCom 正在做的是充当与 USB 串行连接器的单端口连接的管道,然后将所有 I/O 复制到所有客户端都可以连接到的套接字文件服务器,该服务器可以是多个虚拟机或同一虚拟机中的多个串行端口.)
  • c) 启动虚拟机并为您的程序设置一个串行端口,为您的嗅探设置另一个串行端口。噗……就这样吧。

有关如何操作的更多技术细节,请参阅下文...
Linux
如何显示串口?
dmesg | grep tty

这是您要输入的内容,让嗅探器读取输入,假设您选择主动使用串行连接的串行端口位于另一个套接字端口上,例如 com 1 处的 ttyS0(在此示例中 ttyS1 位于 com 3 处)但你可以通过使用 dmesg | grep tty 来解决这个问题)。

看到信息……
jpnevulator --ascii --timing-print --tty "/dev/ttyS1" –read


不相关的信息,您不应该使用,但引导我理解为什么这是错误的方法......

如何映射Linux 中的 com 端口(当您不担心嗅探端口或使用配置添加串行端口时)?
ln -s /dev/ttyUSB0 com3

撤消此类型
unlink com3

其中 ttyUSB0 是从 dmesg | 找到的端口grp tty 和 com3 是 Wine 所需的端口。这是在 ~/.wine/dosdevices 目录中完成的。

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.

圈圈圆圆圈圈 2024-10-06 09:59:55

例如,将电缆从设备的 rx/tx 连接到计算机 com 端口 rx 引脚,并运行终端或串行端口记录器。就这样。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文