Automating serial port communication on Linux Automating serial port communication on Linux linux linux

Automating serial port communication on Linux


Kermit is a serial communication app like minicom and it has its own script language, and I used it for some automatic upload on embedded devices. However, it is quite limited and/or buggy, so I finally switched to using python and pyserial.
Whenever you deal with texte mode, like AT command set or speaking to a shell over a serial line, it is really powerful.

If I need to do binary transfer using some standard protocol, I usually use command line tools in non interactive mode, and spawn them from my python script.

Here is some part of the tools I built : waiting for some input, sending data through xmodem, sending a command to u-boot and starting a transfer using the kermit protocol. I use it for automatic flashing and testing of embedded devices.

class Parser :    def __init__(self, sport_name):        self.currentMsg = ''        if sport_name :            self.ser = serial.Serial(sport_name, 115200)    def WaitFor(self, s, timeOut=None):        self.ser.timeout = timeOut        self.currentMsg = ''        while self.currentMsg.endswith(s) != True :            # should add a try catch here            c=self.ser.read()            if c != '' :                self.currentMsg += c                sys.stdout.write(c)            else :                print 'timeout waiting for ' + s                return False        return True    def XmodemSend(self,fname):        if not self.WaitFor('C', 1) :            print 'RomBOOT did not launch xmodem transfer'            return        self.ser.flushInput()        self.ser.close()        call(["xmodem","-d",self.ser.port,"-T",fname])        self.ser.open() def UbootLoad(self, fname):    self.ser.write('loadb 0x20000000\n')    if not self.WaitFor('bps...',1) :        print 'loadb command failed'        sys.exit()    self.ser.flushInput()    self.ser.close()    retcode=call(['kermit','-y','kermit_init','-s',fname])    if retcode != 0 :        print 'error sending' + fname        sys.exit()    self.ser.open()    self.UbootCmd('echo\n')


I discovered runscript ("$ man runscript"), a utility that adds an expect-like scripting ability to minicom. The expect behavior is useful to me since this device uses a proprietary interactive boot sequence. It's rudimentary but sufficient. A script can be invoked when starting minicom with the "-S scriptname" flag, and specific text from within the script can be sent to a log file, which is useful when running minicom from a script. I haven't found a way to send console content to a log, so having an external script know what's going on inside minicom involves writing to a log and having the script monitor the log. I plan to use runscript only to restart and get to a shell, then ssh to the device for real interaction, within a higher level language script such as Python or Perl. If minicom weren't already in place, I would take shodanex's approach.

Runscript cannot have nested expects. I got around this by using goto's and labels, which is arguably more readable than nested expects anyway:

expect {   "Condition 1"  goto lable1}lable1:    send "something"    expect {       "Condition 2"  goto label2    }lable2:    # etcetera


I'm using such a power controller which I use RS232 to control.

I script it using bash simply by issuing:

echo "your-command" > /dev/ttyUSB0

the specific device I'm using also uses 300 baud rate so I issue:

stty -F /dev/ttyUSB0 300

before hand.