#!/usr/bin/python # -*- coding: utf-8 -*- """ qq - quick terminal Usage: %(progname)s [port [speed]] (default: /dev/ttyS0 115200) qq is a quick and dirty terminal application for beagleboard. I didn't like cu (no CLOCAL that I could find) or minicom (terminal emulation, keyboard shortcuts and configuration got in the way of real work) Except for tilde-specials (similar to rsh, ssh and cu), qq just copies data between the local terminal and the given tty. Two tilde specials are defined: ~.: quit ~b: send break (useful for "alt-sysrq" actions on beagleboard) Copyright © 2009 Jeff Epler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ import atexit import errno import os import select import serial import sys import termios PORT, RATE = "/dev/ttyS0", 115200 if len(sys.argv) > 1 and sys.argv[1] in ("-?", "-h", "--help"): print __doc__ % {'progname': sys.argv[0]} raise SystemExit, 0 if len(sys.argv) > 1: port = sys.argv[1] if len(sys.argv) > 2: rate = int(sys.argv[2]) def do_quit(s): raise SystemExit, 0 def do_break(s): s.sendBreak() specials = { '.': do_quit, 'b': do_break, } class InputStateMachine: BOL, TILDE, MOL = range(3) def __init__(self): self.state = self.BOL def feed(self, data): result = [''] for c in data: if c == '\r': self.state = self.BOL self.add(result, c) elif self.state == self.BOL and c == '~': self.state = self.TILDE elif self.state == self.TILDE: if c in specials: self.add(result, specials[c]) elif c == '~': self.add(result, "~") else: self.add(result, "~" + c) self.state = self.BOL else: self.state = self.MOL self.add(result, c) if not result[-1]: del result[-1] return result def add(self, result, data): if isinstance(data, basestring): result[0] = result[0] + data else: result.append(data) result.append('') IFLAG, OFLAG, CFLAG, LFLAG, ISPEED, OSPEED, CC = range(7) def makeraw(attr): attr = attr[:] attr[IFLAG] &= ~(termios.IGNBRK | termios.BRKINT | termios.PARMRK | termios.ISTRIP | termios.INLCR | termios.IGNCR | termios.ICRNL | termios.IXON); attr[OFLAG] &= ~termios.OPOST; attr[LFLAG] &= ~(termios.ECHO | termios.ECHONL | termios.ICANON | termios.ISIG | termios.IEXTEN); attr[CFLAG] &= ~(termios.CSIZE | termios.PARENB); attr[CFLAG] |= termios.CS8; return attr original_attr = termios.tcgetattr(0) atexit.register(termios.tcsetattr, 0, termios.TCSADRAIN, original_attr) attr = makeraw(original_attr) attr[CC] = ['\0'] * len(attr[6]) attr[CC][termios.VMIN] = 1 termios.tcsetattr(0, termios.TCSADRAIN, attr) s = serial.Serial(PORT, RATE, timeout=0) s.setRtsCts(0) sf = s.fileno() sm = InputStateMachine() while 1: try: r, w, x = select.select([0, s], [], []) except select.error, detail: if detail.args[0] == errno.EINTR: continue raise if 0 in r: d = os.read(0, 1024) for o in sm.feed(d): if isinstance(o, basestring): s.write(o) else: o(s) if s in r: os.write(1, os.read(sf, 1024)) termios.tcflush(0, termios.TCIFLUSH)