#!/usr/bin/env python # # grabserial - program to read a serial port and send the data to stdout # Copyright 2006 Sony Corporation # # This program is provided under the Gnu General Public License (GPL) # version 2 ONLY. # # 2006-09-07 by Tim Bird # # To do: # * buffer output chars?? # * format the time output better # MAJOR_VERSION=1 MINOR_VERSION=0 REVISION=0 import os, sys import getopt import serial import time import re cmd = os.path.basename(sys.argv[0]) verbose = 0 def vprint(message): if verbose: print message def usage(rcode): print """%s : Serial line reader Usage: %s [options] options: -h, --help Print this message -d, --device= Set the device to read (default '/dev/ttyS0') -b, --baudrate= Set the baudrate (default 115200) -w, --width= Set the data bit width (default 8) -p, --parity= Set the parity (default N) -s, --stopbits= Set the stopbits (default 1) -x, --xonxoff Enable software flow control (default off) -r, --rtscts Enable RTC/CTS flow control (default off) -e, --endtime= End the program after the specified seconds have elapsed. -t, --time Print time for each line received. The time is when the first character of each line is received by %s -m, --match= Specify a regular expression pattern to match to set a base time. Time values for lines after the line matching the pattern will be relative to this base time. -v, --verbose Show verbose runtime messages -V, --version Show version number and exit Ex: %s -e 30 -t -m "^Linux version.*" This will grab serial input for 30 seconds, displaying the time for each line, and re-setting the base time when the line starting with "Linux version" is seen. """ % (cmd, cmd, cmd, cmd) sys.exit(rcode) def main(): global verbose # parse the command line options try: opts, args = getopt.getopt(sys.argv[1:], "hd:b:w:p:s:xrtm:e:vV", ["help", "device=", "baudrate=", "width=","parity=","stopbits=", "xonxoff", "rtscts","time", "match=", "endtime=", "verbose", "version"]) except: # print help info and exit print "Error parsing command line options" usage(2) device="/dev/ttyS0" baudrate=115200 width=8 parity='N' stopbits=1 xon=0 rtc=0 show_time = 0 basepat = "" endtime = 0 # get a dummy instance for error checking sd = serial.Serial() for opt, arg in opts: if opt in ["-h", "--help"]: usage(0) if opt in ["-d", "--device"]: device = arg if not os.path.exists(device): print "Error: serial device '%s' does not exist" % device usage(2) if opt in ["-b", "--baudrate"]: baudrate = int(arg) if baudrate not in sd.BAUDRATES: print "Error: invalid baud rate '%d' specified" % baudrate print "Valid baud rates are: %s" % str(sd.BAUDRATES) sys.exit(3) if opt in ["-p", "--parity"]: parity = arg.upper() if parity not in sd.PARITIES: print "Error: invalid parity '%s' specified" % parity print "Valid parities are: %s" % str(sd.PARITIES) sys.exit(3) if opt in ["-w", "--width"]: width = int(arg) if width not in sd.BYTESIZES: print "Error: invalid data bit width '%d' specified" % width print "Valid data bit widths are: %s" % str(sd.BYTESIZES) sys.exit(3) if opt in ["-s", "--stopbits"]: stopbits = int(arg) if stopbits not in sd.STOPBITS: print "Error: invalid stopbits '%d' specified" % stopbits print "Valid stopbits are: %s" % str(sd.STOPBITS) sys.exit(3) if opt in ["-x", "--xonxoff"]: xon = 1 if opt in ["-r", "--rtcdtc"]: rtc = 1 if opt in ["-t", "--time"]: show_time=1 if opt in ["-m", "--match"]: basepat=arg if opt in ["-e", "--endtime"]: endstr=arg try: endtime = time.time()+float(endstr) except: print "Error: invalid endtime %s specified" % arg sys.exit(3) if opt in ["-v", "--verbose"]: verbose=1 if opt in ["-V", "--version"]: print "grabserial version %d.%d.%d" % (MAJOR_VERSION, MINOR_VERSION, REVISION) sys.exit(0) # if verbose, show what our settings are vprint("Opening serial port %s" % device) vprint("%d:%d%s%s:xonxoff=%d:rtcdtc=%d" % (baudrate, width, parity, stopbits, xon, rtc)) if endtime: vprint("Program will end in %s seconds" % endstr) if show_time: vprint("Printing timing information for each line") if basepat: vprint("Matching pattern '%s' to set base time" % basepat) # now actually open and configure the requested serial port # specify a read timeout of 1 second s = serial.Serial(device, baudrate, width, parity, stopbits, 1, xon, rtc) # read from the serial port until something stops the program basetime = 0 linetime = 0 newline = 1 curline = "" vprint("Use Control-C to stop...") while(1): try: # read for up to 1 second x = s.read() # see if we're supposed to stop yet if endtime and time.time()>endtime: break # if we didn't read anything, loop if len(x)==0: continue # ignore carriage returns if x=="\r": continue # set basetime, by default, to when first char # is received if not basetime: basetime = time.time() if show_time and newline: linetime = time.time() elapsed = linetime-basetime sys.stdout.write("[% 12.6f] " % elapsed) newline = 0 # FIXTHIS - should I buffer the output here?? sys.stdout.write(x) curline += x if x=="\n": newline = 1 if basepat and re.match(basepat, curline): basetime = linetime curline = "" sys.stdout.flush() except: break s.close() main()