Can I use the xmodem protocol with PySerial?

2019-03-22 05:58发布

问题:

I have a working connection with my serial device via PySerial, but I also want to transfer files via the xmodem protocol as part of my program.

Which would be the most platform-neutral way to do this? Worst case, I could close() my serial.Serial object in Python and use subprocess to call upon /usr/bin/sb, but that seems inelegant.

I'm currently on Ubuntu 9.10 and am using a USB-TTY adapter.

Any ideas?

回答1:

There is xmodem module on PyPi. It takes two functions in constructor for reading and writing data, implement them to work with your opened serial port. Below is simple sample of its usage:

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


回答2:

I'm not familiar with the details of the xmodem protocol, but one person answering the xmodem-for-python question appears to be, and has even provided what looks like a crude implementation of xmodem in Python. Perhaps you could use that, or ideas from other the answers there.



回答3:

It is super simple to use the XMODEM protocol implementation found on PyPi. A few things to note about the example above is there are some things that are not needed. (Maybe this worked for the author or with a previous version of the module?)

The documentation found here is extremely helpful, so don't let it scare you. You will need a sender and a receiver obviously, and since I do not know which one the Python script will be, here are two examples I have tested and are working below. (basically copied and pasted from the examples on 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)

To receive from the serial device:

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

To send to the serial device:

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

The key here is to be sure the baud rate is set on both sides (defaulting here). Do NOT add any delay or sleep as this is not time based, but transaction based. the prints will allow you to see the transaction real time as the data flows in or out of the file/serial port.