我可以在PySerial中使用xmodem协议吗?

2 投票
3 回答
10783 浏览
提问于 2025-04-15 16:36

我已经通过PySerial成功连接了我的串口设备,但我还想在我的程序中通过xmodem协议传输文件。

那么,最通用的方法是什么呢?最糟糕的情况是,我可以在Python中用close()关闭我的serial.Serial对象,然后使用subprocess来调用/usr/bin/sb,不过这样做感觉不太优雅。

我现在使用的是Ubuntu 9.10,并且在用USB-TTY适配器。

有没有什么好的建议呢?

3 个回答

0

我对xmodem协议的具体细节不是很了解,但在回答xmodem-for-python这个问题的人似乎很懂这个协议,并且还提供了一个看起来很简单的xmodem在Python中的实现。也许你可以参考一下这个实现,或者看看其他回答中的想法。

2

使用在PyPi上找到的XMODEM协议实现非常简单。上面例子中有一些不必要的东西,可能是作者之前的版本有效吧?

这里的文档 非常有帮助,所以不要被它吓到。你显然需要一个发送方和一个接收方,而我不知道Python脚本会是哪个,所以下面是我测试过并且有效的两个例子。(基本上是从PyPi的例子中复制粘贴过来的)

import serial
from xmodem import XMODEM

ser = serial.Serial(port='COM56')


def getc(size, timeout=8):
    gbytes = ser.read(size)
    print(f'Read Byte: {gbytes}')
    return gbytes or None


def putc(data, timeout=8):
    pbytes = ser.write(data)
    print(f'Put Byte: {pbytes}')
    return pbytes or None


if __name__ == '__main__':
    modem = XMODEM(getc, putc)

从串口设备接收数据:

stream = open('output', 'wb')
modem.recv(stream, crc_mode=0)

向串口设备发送数据:

stream = open('input', 'rb')
modem.send(stream)

这里的关键是确保两边的波特率设置一致(这里是默认设置)。不要添加任何延迟或休眠,因为这个不是基于时间的,而是基于事务的。打印输出可以让你实时看到数据是如何进出文件或串口的。

4

在PyPi上有一个叫xmodem的模块。它的构造函数需要两个函数,分别用于读取和写入数据。你需要把这两个函数实现出来,以便和你打开的串口进行通信。下面是一个简单的使用示例:

import serial
try:
    from cStringIO import StringIO
except:
    from StringIO import StringIO
from xmodem import XMODEM, CRC
from time import sleep

def readUntil(char = None):
    def serialPortReader():
        while True:
            tmp = port.read(1)
            if not tmp or (char and char == tmp):
                break
            yield tmp
    return ''.join(serialPortReader())

def getc(size, timeout=1):
    return port.read(size)

def putc(data, timeout=1):
    port.write(data)
    sleep(0.001) # give device time to send ACK


port = serial.Serial(port='COM5',parity=serial.PARITY_NONE,bytesize=serial.EIGHTBITS,stopbits=serial.STOPBITS_ONE,timeout=0,xonxoff=0,rtscts=0,dsrdtr=0,baudrate=115200)
port.write("command that loads data via xmodem\r\n")
sleep(0.02) # give device time to handle command
readUntil(CRC)
buffer = StringIO('data to send')
XMODEM(getc, putc).send(buffer, quiet = 1)
buffer.close()
readUntil()

撰写回答