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.