Automating serial port communication on Linux
Asked Answered
N

7

13

I have a linux server (Red Hat 4) with one serial port connection to an embedded linux device, and another serial port connection to a power controller for that device. My current way to control them is to open two minicom sessions, each in its own window. I would like to automate this communication through scripts. At first, I began to think how I could automate using minicom, then realized I shouldn't need to try to automate using a console application when a script should be able to speak to the port directly.

I know some Perl and some python. I do not have previous experience with modem communication (using AT commands). Perl has Device::Modem, though it's only beta, and Perl seems like a good choice because I prefer its text extraction and wrangling abilities. But, if I need to learn how to control a modem and write/debug a script, that adds more time to my task.

Is it possible/common to interactively control a console app like minicom with a script? If not, what are some good resources for me to learn how to use modem AT commands? Or is there another resource out there that could simplify things for me?

Nellnella answered 6/10, 2010 at 16:11 Comment(0)
O
6

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')
Orthopedist answered 7/10, 2010 at 7:24 Comment(1)
Thanks! I discovered minicom has a utility called runscript, which is rudimentary but sufficient. However, thank you very much for posting that. I may very well find that useful in the future.Nellnella
N
6

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
Nellnella answered 8/10, 2010 at 14:10 Comment(3)
Correction: When minicom is invoked with "-C logfilename" then console output is captured to that file.Nellnella
You have typos in your script, "lable" vs. "label".Nagey
runscript looks OK but I couldn't see a way to send a file so pyserial it is for me.Nonstriated
A
3

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.

Adan answered 7/10, 2010 at 10:15 Comment(0)
T
2

If it's just about controlling the devices and nothing else (like processing messages, interacting with other operating system services, etc) you can use the chat program. It's written exactly for this. You may find it in the ppp package on any Linux distro.

Tiffanytiffi answered 6/10, 2010 at 16:17 Comment(1)
Thank you for telling me about the chat program. It could address part of my needs, but I actually have to be able to download and boot a new linux image to this device before getting to the shell. The device uses busybox.Nellnella
E
1

Python now has the PySerial library: http://pyserial.sourceforge.net/

Ruby has the SerialPort gem: http://rubygems.org/gems/serialport

Perl probably has a similar library, but I was unable to find it.

I discovered both of these from the very useful Arduino Playground: http://playground.arduino.cc//Main/Interfacing

CJ

Everyway answered 10/6, 2013 at 13:54 Comment(0)
M
0

Answer using picocom

#!/bin/bash

# barf on error
set -e
# configure port, exit immediately, don't reset
picocom -qrX -b 115200 ... other settings ... /dev/ttyS0
# send contents of cmd.txt, line by line, 
# waiting 1 sec in-between, after host sends reply
while read ln; do
     echo "$ln" | picocom -qrix 1000 /dev/ttyS0
done < cmd.txt

Taken from link

Or in one line:

echo "command" |  picocom -qrx 1000 /dev/ttyS0 
Mahmoud answered 29/7 at 10:31 Comment(0)
M
0

Answer using socat

echo "command" | socat - /dev/ttyUSB0,crnl
Mahmoud answered 19/8 at 10:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.